Laure Potet

Mr Aurélien Francillon

Mr Sébastien Pillement

for willing to serve on my thesis committee. They carefully attended my defense, listened to my vision regarding my research, evaluated it, recognized it, and finally, awarded me with the degree of doctor. Their insightful comments, suggestions, and challenging questions have helped me make significant improvements to this thesis and beyond. We had memorable discussions and interesting debates during the defense

Introduction

Introduction

W ith the emerging technologies in several domains such as artificial intelligence, communication, sensors, and processing power, manufacturers are increasingly developing new ubiquitous connected devices identified as the "Internet of Things" -IoT-. According to Forbes [1], the IoT is a fast-growing market that may even double before 2021. As a result, manufacturers see in IoT a genuine business opportunity that encourages them to increasingly release new smart devices over the coming years.

The prime purpose of IoT devices is to operate in an environment by collecting, processing, and sharing data over the network with other computers without any human-to-human or human-to-computer interaction. From the consumers' perspective, smart devices are technological innovations that aim at improving their daily life. One of the most common applications example of the "Internet of Things" is the smart home. In a smart home, a user can monitor some equipment such as the lights, the temperature, and the appliances by only using a smartphone. However, the "Internet of Things" is not limited to smart homes. Several sectors [START_REF] Chiang | Fog and IoT: An Overview of Research Opportunities[END_REF] such as agriculture, transport, healthcare, and the military are heavily invested in the development of innovative IoT infrastructures to improve their quality of life and quality of service.

This thesis unfolds within the European project SERENE-(IoT Secured & EneRgy

EfficieNt hEalth-care solutions for IoT market). SERENE-IoT project is labeled within the framework of PENTA, the EUREKA Cluster for Application and Technology Research in Europe on NanoElectronics. The project contributes to developing high quality connected care services and diagnostic tools based on advanced smart health-care IoT devices. SERENE-IoT leverages the emergence of the "Internet of Medical Things" -IoMTto prototype new devices, fully manufactured in Europe, that increases the healthcare quality of service for patients remotely followed by caregivers at a much lower cost than the traditional care.

Unfortunately, connecting medical devices to the network is a concern. It raises relevant questions especially in the areas of privacy, security, and safety [3]. The main purpose of this thesis performed within the CTSYS team of the Laboratoire de Conception et d'Intération des Systèmes (LCIS) in Valence and collaboration with the University of Arizona in Tucson is to focus on the embedded system application security of the next generation of IoMT. However, before digging into the security concerns that impact medical devices, it is important to define what is a medical device. According to the Food and Drug Administration (FDA) [4], a medical device is "an instrument, apparatus, imple-Introduction ment, machine, contrivance, implant, in vitro reagent, or other similar or related article, including a component part or accessory which is: recognized in the official National Formulary, or the United States Pharmacopoeia, or any supplement to them, intended for use in the diagnosis of disease or other conditions, or in the cure, mitigation, treatment, or prevention of disease, in man or other animals, or intended to affect the structure or any function of the body of man or other animals, and which does not achieve its primary intended purposes through chemical action within or on the body of man or other animals and which is not dependent upon being metabolized for the achievement of any of its primary intended purposes". For instance, two medical devices are shown in Figure 1. On the left, a pacemaker used in the treatment of heart diseases. On the right, an insulin pump commonly used in the treatment of diabetes.

Figure 1: Off-the-shelf medical devices

In consistence with healthcare manufacturers, the main purpose of connecting these two medical devices is to improve the quality of service. It may help healthcare professionals in the prevention, diagnosis, and treatment of patients' disease. From the patient perspective, wireless medical devices improve the quality of life. For instance, it is much less restrictive to update a pacemaker using the Bluetooth TM [5] protocol rather than performing surgery. Thus, healthcare manufacturers see IoMT as a way to revolutionize and improve patient care. Thanks to connectivity many medical devices may help healthcare professionals to identify early disease at the lowest cost but also to monitor and adjust the progress of a patients' treatment over time [3].

A representative example of a wireless medical device is a connected insulin pump.

Insulin pumps are commonly used in the treatment of diabetes. Today, according to the World Health Organization (WHO) [START_REF]Faits et chiffres sur le diabète[END_REF] it is more than 8% of the worldwide population that suffers from diabetes. To stay alive, these people must regularly inject themselves manually with insulin to keep their blood sugar at a reasonable threshold. Although this practice is necessary, it remains very binding for patients. Thanks to new IoMT devices such as wireless insulin pump [START_REF] Medtronic | Minimed Pump 512[END_REF][START_REF] Melmer | Glycaemic control in individuals with type 1 diabetes using an open source artificial pancreas system (openaps)[END_REF] the process of measuring and self-injecting the insulin is automated and even remotely controlled. As a result, the quality of life and comfort of patients significantly improved. implanted under the skin that measures glycemia at regular intervals. These measurements are sent to a remote smartphone application that computes and determines whether the blood glucose is too high (1 in Figure 2). If the glycemia is too high, a bolus injection command is sent from the smartphone to the insulin pump (2 on Figure 2). Usually, these commands are sent using a low-energy radio protocol such as Bluetooth TM [5]. Once received, the command is processed and injects an insulin bolus to the patient. Finally, the injected insulin maintains the glycemia of the patient that is again measured by the CGM forming the closed-loop system (3 on Figure 2).

The extension of connected devices such as insulin pumps in the healthcare industry is a promising innovation and will undoubtedly bring many benefits to both caregivers and patients. However, as previously stated, connecting medical devices to the network is a concern. Indeed, a large majority of medical devices such as pacemakers, insulin pumps, defibrillators are considered life-critical systems. In other words, these devices are in direct interaction with the human body and may harm in the event of a hazard or even worse, a security breach. Of course, healthcare manufacturers are well trained about safety issues and various hazards in medical devices for decades. Many medical devices on the market have been validated by recognized institutions such as the FDA [4] and to date are considered very safe. However, it appears that manufacturers are less aware of cybersecurity issues [START_REF] Lily | Medical Devices Are the Next Security Nightmare[END_REF]. This is because connecting a medical device to the network is a relatively recent trend. Consequently, these devices are more exposed to new threats that manufacturers were not confronted with in the past. Introduction are usually poorly achieved. Furthermore, advanced vulnerability research should be part of the development life cycle of a medical device. However, this is rarely the case, advanced security tests are time and budget consuming making them regularly neglected.

For hackers, this lack of robust security trends is profitable. In recent years, many new attacks have appeared on various life-critical systems. For instance, security researchers were able to maliciously modify the firmware of a real infusion pump [START_REF] Kim | Hacker can send fatal dose to hospital drug pumps[END_REF] and pacemakers [START_REF] Newman | A New Pacemaker Hack Puts Malware Directly on the Device[END_REF] because there were not properly signed by the manufacturers. As a result, these researchers were able to implement malware directly in the device. Also, many wireless medical devices do not verify the authenticity and the identity of the host with whom they interact. Hence, a malicious hacker can easily craft a fake application [START_REF] Lily | These Hackers Made an App That Kills to Prove a Point[END_REF] and send malicious commands to the critical device. Many medical devices use a proprietary protocol for communication. Unfortunately, these protocols do not use proper or standard ciphers leaving the data in plain text passing through the network [START_REF] Lily | These Hackers Made an App That Kills to Prove a Point[END_REF]. As these devices are connected to the network, they can also be remotely accessed. Unfortunately, once again, the accesses are often poorly secured, and even sometimes, there is no security at all [START_REF] Kim | Video Shows a Terrifying Drug Infusion Pump Hack in Action[END_REF]. On top of that, medical devices are vulnerable to zero-day vulnerabilities such as memory safety issues that result from code and design mistakes [15]. These vulnerabilities can be exploited by hackers to remotely execute malicious code on the device. The seriousness of this type of attack is extreme, it can be achieved without requiring any physical access to the system. In an era of ransomware [START_REF] Labs | 2017 Threats Predictions[END_REF], such poor security devices are profitable to hackers that look for a quick return on investment. Since these critical-devices keep patients alive, it's even easier for hackers to pressure them to pay a ransom.

As it appears, there are various vulnerabilities in medical devices. Countermeasures against these vulnerabilities cover many areas of software and hardware security. This thesis focuses on embedded software security. More, specifically the thesis studies the memory safety issue in life-critical devices. When exploited, memory safety issues allow attackers to take control of a device and make it execute arbitrary malicious actions. While the criticality of these vulnerabilities is severe, and even more when it can be performed remotely, it seems that efficient protections are currently not deployed in medical devices [START_REF] Lily | Medical Devices Are the Next Security Nightmare[END_REF][START_REF]Hospira Multiple Products Buffer Overflow Vulnerability[END_REF][START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF].

To address these concerns, this manuscript proposes the following steps. The first chapter covers the state-of-the of various attacks and defenses regarding memory safety.

It highlights the particularities of critical embedded systems such as medical devices, why they are exposed to memory safety issues, how memory safety vulnerabilities are exploited, and finally, what are the existing defenses. Chapter 2 confronts the state of the art with the requirements of life-critical medical devices. More specifically, this transitional chapter identifies why current medical devices do not benefit from existing defenses. Then, it exposes the problem: How to implement practical and efficient defense against memory safety defenses in safety-critical devices while respecting their constraints? The thesis proposes to deal with this problem using two approaches and a life-critical demonstrator to assess them. Chapter 3 exposes SecPump, a wireless insulin pump security system work-Introduction bench used to model memory safety threats and tailored for further security assessments.

Chapter 4 presents TrustFlow, the first approach of the thesis. This approach assumes that memory safety defenses can be implemented using both hardware and software. As a whole, TrustFlow is a framework that ensures low-level software protection specifically for memory-constrained embedded systems. Conversely, Chapter 5 presents BackGuard, the second approach of the thesis. Unlike the first approach, this approach assumes that most critical embedded applications are running on a fixed microprocessor that cannot be modified to implement security features. As a result of this assumption, this second approach aims to demonstrate and study the feasibility of memory safety defenses using only software primitives.

Background

Summary of the Chapter

This Chapter surveys the memory-safety issue in embedded systems. As this thesis unfolds in the medical area, a brief introduction to life-critical devices is given at the beginning of the Chapter. This introduction describes how these systems work, how they are designed, and why they are currently facing memory safety issues. The Chapter offers an overview of the various attack techniques that are leveraged by an attacker to execute malicious code on a system. Then, it exhibits the state-of-art regarding the existing countermeasures. This state-of-the-art regroups the countermeasures in four categories exposing their benefits, costs, and weaknesses. Finally, synthesis of the state of the art prepares the gap exposure and the thesis approach outlined in Chapter II.

Chapter 1. Background

The Memory Safety Issue in Life-Critical Systems 1.C a prominent programming language in critical systems

Life-critical systems such as wireless insulin pumps described are governed by both hardware and software components. One of the fundamental aspects of these components is that they should meet high performance and deterministic real-time constraints to deliver the patients' perfect dose of insulin at the right time. Also, for patient-worn systems, the components must be small in order not to be too invasive. The logical and deterministic actions performed by cyber-physical systems are driven by thousands of lines of code that are executed by microcontrollers. Microcontrollers are often considered as the brain of smart devices. They execute instructions that control and deliver input/output to external components. These external components include drug reservoirs, screens that establish physical contact between the user and the embedded system, sensors, and radio components. Finally, the set of lines of code that lead the logic of the system constitutes the firmware. Its main purpose is to monitor the behavior of the device throughout its lifetime.

According to a recent study made by the IEEE Spectrum 2017 [START_REF] Stephen | IEEE Spectrum -The 2017 Top Programming Languages[END_REF], the C programming language is the dominant language in the context of embedded system programming.

Most of the existing critical devices' firmware on the market are developed using the C programming language [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF]. This popularity can be explained by several advantages that this C offers to critical embedded systems manufacturers over other programming languages:

• Maturity: The C programming language has been created more than 40 years ago to provide an alternative to writing code in assembly. Since then it has been widely used in companies and academia. Compared to much newer programming languages [START_REF] Donovan | The Go programming language[END_REF][START_REF] Matsakis | The rust language[END_REF], the C programming language has the advantage of being supported by a large and experienced community.

• Readability: C is considered a high-level programming language in comparison with assembly. It has been created to write data structures and algorithms without relying on complex assembly knowledge.

• Toolchain support: Many free C compilers [START_REF] Griffith | GCC: The Complete Reference[END_REF], [START_REF] Lattner | LLVM: A compilation framework for lifelong program analysis & transformation[END_REF], and libraries are available for a wide range of microcontrollers. This means that the C programming language can be easily translated into efficient machine-independent code. On top of that, the current C compilers are very mature and offer a lot of features such as detecting programming errors during compilation and/or code coverage [START_REF] Griffith | GCC: The Complete Reference[END_REF]. Also, many free open-source and well-maintained toolchains are available to perform either static [START_REF] Lattner | LLVM: A compilation framework for lifelong program analysis & transformation[END_REF][START_REF] Cuoq | Frama-c[END_REF], and/or dynamic [START_REF] Nethercote | Valgrind: a framework for heavyweight dynamic binary instrumentation[END_REF][START_REF] Serebryany | Addresssanitizer: A fast address sanity checker[END_REF] verification of C programs.

• Modularity: The C programming language is very modular, thanks to header files it allows developers to export functionality from a C source file and import it in another 1.1. The Memory Safety Issue in Life-Critical Systems file. Consequently, by using modularity it is very easy for a programmer to break a complex program into multiple sub-modules that achieve specific functionalities.

• Portability: Many free C compilers are available for a wide range of Instruction Set Architecture (ISA). This means that the C programming language enables developers to write convenient processor independent code that ensures low-level tasks while retaining portability.

• Efficiency: The C programming language can easily interface with other programming languages such as assembly. In embedded system programming, it is very common to see routines that are completely written in assembly to efficiently use the hardware. Secondly, one of the most powerful features offered by the C programming language is full control over memory management thanks to pointers. Indeed, by using pointers, embedded system developers can directly read/write from/to memory or allocate it in an efficient, machine-independent way. Consequently, embedded systems programmers can customize the memory usage of embedded systems applications making it inherently fast and optimized in size. Finally, as most of the embedded systems have input/output devices that are directly mapped into the memory, the use of pointers allows instant access to these memory locations.

• Real-time operating system support: On the market, the most popular real-time operating systems [START_REF]Threadx real-time operating system[END_REF][START_REF] Arm | Mbed OS[END_REF][START_REF] Barry | Freertos[END_REF][START_REF] River | VxWorks[END_REF] are written in the C programming language. The C programming language is very fast and efficient; it can easily meet real-time constraints.

Besides, these real-time operating systems provide C APIs enforcing the use of this language by developers.

• Determinism: C programs can be written to be deterministic. This means that it is formally possible to determine the behavior of a program knowing its current state, the previous events, and the environment. Determinism is a very strong feature for critical systems because it allows manufacturers to develop very accurate programs.

• Standard: The C programming language is compliant with safety-critical standards such as the DO-178C [START_REF] Rierson | A Practical Guide for Aviation Software and DO-178C Compliance[END_REF] and MISRA C [START_REF] Bagnara | The misra c coding standard and its role in the development and analysis of safety-and security-critical embedded software[END_REF].

It turns out that the C programming language is a perfect language for critical systems. The language is close to the hardware, allowing developers to tune specific routines and memory allocation. This programming language can be used to develop lightweight applications that are very fast, deterministic, safe, and portable.

Unfortunately, these benefits come at a certain price. The C programming language does not provide any specific security support against memory access mistakes. This can lead to several security breaches covered in the following section.

The C programming language weaknesses

While the C programming language provides many benefits to embedded system developers, it is often the source of numerous in-memory security flaws due to the misuse of Chapter 1. Background pointers. To understand the origin of in-memory security flaws, it is important to introduce the basic memory layout of a C program.

A simplified example of a C program is displayed in Figure 1.1.

Figure 1.1: C program memory layout

Several variables in the displayed program are annotated with bullets. When compiled into instructions, the program is mainly stored on the "text" memory section of the microcontroller. When executed, this program performs computations using variables that are stored in several areas of the memory.

The variable (1) is an uninitialized global variable. It is stored in the Block Started by Symbol (BSS) area of the memory. This global variable can be accessed throughout the entire lifetime of the program by any function. If it turned out that the variable was initialized it would be placed in the data section.

Both variable [START_REF] Chiang | Fog and IoT: An Overview of Research Opportunities[END_REF] and (3) are used within a function, their scope is limited to the life span of the main function. Regarding the microcontroller memory, these temporary variables are placed in the stack area. The stack is a memory structure that follows the Last-In-First-Out (LIFO) concept. In Figure 1.1, the stack is ascending downwards. The stack memory structure is addressed by the stack pointer register of the microprocessor core. This register always points to the memory address of the top of the stack. Two main operations manage the stack: push and pop. When data is pushed, the stack pointer moves to the lowest adjacent address, and the corresponding data is stored. When data is popped, the data stored at the stack pointer address is returned and the pointer moves to the highest adjacent address. Considering our example, when the main function executes,

(2) and (3) are pushed on the stack and destroyed when the function returns.

The variable (4) is slightly different from the variable (2) and (3). Indeed, the variable (4) is a pointer stored on the stack but points on a freshly allocated memory which is located in the heap area thanks to a memory allocation function. In Figure 1.1, the heap memory area is increasing upwards. The heap is governed by specific memory allocation algorithms that depend on the "malloc" implementation. Each memory chunk allocated in the heap is accessible by a program through the use of pointers. Besides, allocated 1.1. The Memory Safety Issue in Life-Critical Systems memory chunks can be freed thanks to the "free" function.

Finally, the variable (5), is a static initialized variable. This variable is placed into the data memory section and its value is preserved even when the main function returns.

However, this variable is considered private and can only be accessed by the main function.

Knowing the structure of a C program in memory, it is now possible to point out its weaknesses. Unlike high level and/or interpreted programming languages [START_REF] Arnold | The Java programming language[END_REF][START_REF] Rossum | Python reference manual[END_REF], the C programming language does not provide any extra features for spatial and temporal memory safety. The C programming language is thus considered unsafe. Spatial memory safety is defined as the property that all memory objects are always accessed within their bounds. In other words, the C programming language does not ensure that the data copied into a buffer will no longer be larger than the buffer can hold. It follows, that if a developer does not explicitly check for oversized input, an attacker can intentionally provide large enough data that will write past the end of a buffer. As a result, adjacent memory areas that do not belong to the buffer will be overwritten, leaving the program in an erratic state. The most prominent example of a spatial memory error is a stack buffer overflow/underflow. A classical stack buffer overflow is displayed in Figure 1.2. In such a situation, an attacker overflows a local buffer on the stack and overwrites useful buffers' adjacent data of the program. In Figure 1.2, the "stack_buffer" buffer is in the stack area and the "strcpy" function copies a buffer coming from "argv [1]" which is controlled by an attacker. Unfortunately, the "strcpy" function does not check the size of "argv [1]" before copying it to the "stack_buffer" buffer. Consequently, an attacker can exploit this feature to modify some data in the memory that does not belong to the buffer. Thus, if this data is reused later, the behavior of the program may be modified. It should be mentioned that spatial vulnerabilities are nowadays much more complex than the straightforward example displayed in Figure 1.2 [START_REF] Ablon | Zero days, thousands of nights: The life and times of zero-day vulnerabilities and their exploits[END_REF].

Figure 1.2: Spatial memory issue

Temporal memory safety is defined as the property that ensures that all memory objects are valid at the time they are dereferenced by a pointer. Like spatial memory safety, the C programming language does not prevent any attempts to read or write an object after it has been deallocated. It follows that, after deallocating an object in memory, Chapter 1. Background if the developer does not explicitly invalidate all pointers on this object, some will still point to the freed memory location. These pointers are called dangling pointers; they can dereference invalid memory location. By leveraging dangling pointers, an attacker can intentionally reallocate the previously freed memory, fill it with malicious data, and dereference a dangling pointer to this location. As a result, the previously deallocated object is reused thanks to the dangling pointer with invalid data causing unexpected memory corruption.

Figure 1.3: Temporal memory issue

A typical dangling pointer scenario is displayed in Figure 1.3. This example assumes that an attacker can use object A and free it thanks to the pointer A. Also, it assumes that object A has previously been allocated by the application (1) and cannot be modified by an attacker. However, the example assumes that an attacker can fully allocate an object B and modify it. By leveraging this dangling pointer issue, an attacker can launch a memory attack in three steps. First, the attacker makes the application free object A in memory [START_REF] Chiang | Fog and IoT: An Overview of Research Opportunities[END_REF]. Due to the vulnerability, pointer A is still pointing to invalid memory object A. Then, the attacker allocates a new object B and fills it with custom data (3). Finally, the attacker makes the application reuse the pointer A which is pointing on an invalid controlled object B. As a result, the application executes code that belongs to object A but with object B values. As spatial attacks, dangling pointers can be maliciously manipulated by attackers to make an application execute invalid data.

The incorrect verification of oversized input and the usage of freed memory are common programming vulnerabilities related to the usage of the C programming language [START_REF] Mitre | CWE Top 25 Most Dangerous Software Errors[END_REF]. Nowadays, buffer overflows and dangling pointers, represent a significant part of the low-level security bugs [15,37]. Their exploitation has many consequences from crashing a target application to executing user-supplied malicious code. This thesis is chiefly concerned about malicious code execution on critical devices. Indeed, the ability of an attacker to induce faulty behavior into a critical system is a significant threat that can lead to disastrous consequences.

To understand arbitrary code execution on embedded devices, Figure 1.4 exposes the concept of control-flow graphs. It turns out that every function transition in an application is governed by control-flow information. This control-flow information is either immutable in the source code (direct forward-edge) or calculated at run-time through a function pointer (indirect forwardedge) and/or function return address (indirect backward-edge). Unlike fixed control-flow information, indirect control-flow transitions are usually computed at run-time and stored in either registers or memory. Thus, from the moment control-flow information is stored in memory it can be tamper through the exploitation of one of the previously exposed vulnerabilities such as buffer overflows or dangling pointers.

A typical control-flow attack is performed at run-time when data is exchanged between a malicious user and the application. The main goal of a control-flow attack is to hijack the execution flow of an application and make it execute malicious actions. For instance, a spatial memory vulnerability can be exploited by an attacker to write past beyond the limit of a buffer. Thus, the attacker possesses an arbitrary write in memory that may Chapter 1. Background overwrite control-flow information located close to the buffer. By replacing in-memory control-flow information, an attacker can divert the execution flow on a destination of his choice.

Nowadays, every embedded system written in C can be vulnerable to memory corruption bugs. Even with extremely accurate and advanced tests, the time proved that some memory bugs remain undetected [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF][START_REF] Ablon | Zero days, thousands of nights: The life and times of zero-day vulnerabilities and their exploits[END_REF]. However, these memory bugs can potentially threaten the security of a system after being discovered by attackers. Unfortunately, there are still a lot of reasons why the memory safety issue is far from being solved in critical IoT devices:

• Device complexity: Connected devices especially life-critical devices in healthcare are becoming increasingly complex. These devices have to deal with hard real-time constraints and deterministic behavior in any condition. For instance, an infusion pump in its intended operating mode had to deliver the perfect amount of insulin when needed without misbehaving due to physical external factors. Besides, some embedded software may control physical devices. These physical devices can be the source of high pressure or X-ray control and therefore extremely difficult to debug when controlled by software. Finally, the combination of several physical elements controlled by software increases the complexity of a system, its safety analysis, and the implementation of accurate tests that cover all functionalities without unwanted bugs.

• The number of lines of code: There are no existing metrics that give the average bugs per line of code. However, it is often considered that there are between 15 and 50 bugs per 1000 lines of code [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF]. Applied to a pacemaker which is around 80,000 lines of code [START_REF] Harris | Open-source medical devices: When code can kill or cure| the economist[END_REF], an infusion pump which is around 170,000 lines of code [START_REF] Harris | Open-source medical devices: When code can kill or cure| the economist[END_REF] or a magnetic resonance imaging which is around 7 million lines of code [START_REF] Harris | Open-source medical devices: When code can kill or cure| the economist[END_REF], there is a high probability that some memory bugs remains undetected after tests and attackers are looking for them.

• Third-party services: When developing a critical application, it may require the use of libraries or third-party code. Although it is possible to test these third-party codes before integrating them, this operation may require non-trivial reverse engineering skills due to the unavailability of the source codes.

• Increased attack surface: From the three previous points it follows that the attack surface of a system is directly proportional to its complexity, its number of lines of code, and its number of integrated third-party code. Hence, the more complex the system proves to be, the more likely it is that attackers will find vulnerabilities. Also, with the Internet of Things trend, more and more manufacturers are connecting devices to the Internet and critical medical systems are no exception [START_REF] Lily | Medical Devices Are the Next Security Nightmare[END_REF].

Unfortunately, the connectivity sharply increases the attack surface. Indeed, with a memory vulnerability, an attacker is now able to remotely control a critical system. Finally, while the C programming language offers fine control over embedded systems, 1.1. The Memory Safety Issue in Life-Critical Systems this section demonstrated that it comes with a certain security cost. As extensively discussed, the C programming language does not provide any safeguard against memory safety issues. One can argue that the exploitation of memory corruption bugs is not new and the ways to overcome it have been studied over the past twenty years [START_REF] Szekeres | Sok: Eternal war in memory[END_REF]. Unfortunately, it seems that critical devices are still vulnerable to it [15,37].

Critical systems programming rules

The usage of the C programming language in critical embedded systems differs from traditional desktop applications. Life-critical medical devices can mean the difference between life and death. To release medical devices on the market, manufacturers closely follow important standards such as the IEC 62304 [START_REF][END_REF], a functional safety standard that specifies the software requirements for medical devices, the ISO 14971 [42] for the risks managements, the ISO 13485 [43], a set of procedures guaranteeing the quality monitoring, and finally, the FDA regulations [START_REF] Fda | Electronic signatures final rule, 21 cfr part 11[END_REF] concerning medical records and device traceability.

These certification standards assess the quality and the safety of medical devices software based on the development process [START_REF] Ferdinand | Static memory and timing analysis of embedded systems code[END_REF]. Regarding the implementation, the IEC 62304 [START_REF][END_REF] strongly enforces the use of coding standards such as MISRA [START_REF] Bagnara | The misra c coding standard and its role in the development and analysis of safety-and security-critical embedded software[END_REF] to enforce safety. By respecting these guidelines, manufacturers reduce the likeliness of software hazards and they allow certification of their products. While these standards ensure quality, reliability, and safety, it should be mentioned that they do not remove security issues related to memory safety [15,[START_REF]Hospira Multiple Products Buffer Overflow Vulnerability[END_REF]37].

To avoid the use of long and complex (sometimes vague) coding standards, the Jet Propulsion Laboratory (JPL) of NASA proposes the "The Power of Ten -Rules for Developing Safety Critical Code" [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF]. This paper summarizes some strict development rules to write safety-critical applications using the C programming language. The JPL argues that 10 rules are not all-inclusive but it is enough to achieve measurable effects on software reliability. These 10 rules mostly summarize the highest coding standards such as MISRA [START_REF] Bagnara | The misra c coding standard and its role in the development and analysis of safety-and security-critical embedded software[END_REF]. This thesis considers that most life-critical medical devices enforce these rules. Consequently, the security contributions detailed in the following thesis are designed in accordance with [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF]. More specifically, the security contributions will at a minimum be able to protect systems that comply with the 10 rules enforced by the JPL. Not all the rules are mentioned in this manuscript. Some of them encourage the improvement of code quality in safety-critical applications. For in-depth details, the thesis refers the reader to "The Power of Ten -Rules for Developing Safety Critical Code" paper [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF]. However, bellow is three important rules that have an impact on the outcome.

• Use of simple control-flow structures: No "setjmp", "longjmp", "goto" or direct/indirect recursion: By respecting simple control-flow structures developers improve the clarity of an application and make debugging easier. Moreover, the use of recursion introduces cycles into control-flow graphs that complicate the verification task of static analyzers. Besides, it is not an easy matter to cover all the tests to Chapter 1. Background determine the upper bound of a recursive function. As a consequence, recursion can induce prohibitive unexpected large usage of stack memory in life-critical systems.

Finally, according to [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF], a recursive function can always be translated into iterative function.

• No dynamic memory allocation after initialization: According to [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF][START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF] and most of the references in critical software development [START_REF] Rierson | A Practical Guide for Aviation Software and DO-178C Compliance[END_REF][START_REF] Bagnara | The misra c coding standard and its role in the development and analysis of safety-and security-critical embedded software[END_REF], the use of dynamic memory allocation using "malloc" introduces memory pool fragmentation and potential memory leakage (dangling pointers).

It follows that the usage of dynamic memory allocation is not deterministic and thus cannot be safe.

• No more than one level of pointer dereferencing: The use of pointers is one of the major sources of programming errors, safety, and security issues. Although their use may be practical, it must be minimized and restricted to the smallest scope as possible. Moreover, according to [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF], the use of function pointers should be justified and even prohibited. Indeed, when checking an application, the use of a function pointer prevents static analysis tools from determining a call destination and the absence of recursion. However, after being reviewed 10 years later [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF], it seems that the JPL considers that "constant function pointers, for instance, stored in lookup tables, pose no risk to safe execution or code analysis".

Considering the previous rules and with section 1.1.2, life-critical application mostly consumes static memory. Consequently, most memory vulnerabilities are located in static regions such as the stack, the data, and the BSS. In critical embedded systems, temporal memory safety issues are restricted by the non-use of dynamic memory allocation.

Exploitation Techniques

Exploitation Techniques

A successful memory attack results from the exploitation of a spatial and/or temporal memory issue. The main goal of a memory exploit is to divert the execution flow of an application to make it trigger malicious actions. This section highlights the various exploitation techniques used by both attackers and researchers to hijack the behavior of a program. The state-of-the-art is carried out in two parts: control-flow attacks and dataoriented attacks. Control-flow attacks aim at diverting the execution flow of a program by violating its control-flow graph whereas data-oriented attacks break the logical behavior of an application without necessarily violating the control-flow graph.

Control-flow attacks

This section discusses various control-flow attacks. More specifically, control-flow attacks mostly rely on malicious code injection and/or code-reuse techniques.

Code-injection attacks

Historically, the first control-flow attacks were based on code injection [START_REF] One | Smashing The Stack For Fun And Profit[END_REF]. To illustrate the code-injection process this section refers to Figure 1.5.

Figure 1.5: Stack-based buffer overflow issue

A trivial example of a buffer overflow vulnerability is displayed on the code part of the Figure. A primary function "main" is calling a "vuln" function with a buffer argument. Such code can be easily represented by a basic control-flow graph with two vertices (on the bottom in Figure 1.5). The zoom on the stack memory area is particularly interesting in this example because this is exactly where an attacker achieves his attack. First, the "vuln" function (1) is called by the "main" function. This has the effect of saving the return address (1) of the "vuln" function in the stack. Indeed, after its execution, the Chapter 1. Background "vuln" function must return to the "main" function to continue execution. To achieve this, the "vuln" function needs control-flow information stored in memory such as the saved return address. Then, a buffer (2) is also stored in the stack area (2) of the "vuln" function. According to Figure 1.5, the buffer is close to the return address stack. Finally, the "strcpy" function is used to copy data controlled by an attacker in the stack buffer [START_REF] Chiang | Fog and IoT: An Overview of Research Opportunities[END_REF]. As the "strcpy" does not perform any bounds checking while copying the attacker data in the stack buffer, a spatial memory vulnerability can be exploited. Such a spatial attack is shown in Figure 1.6. First, an attacker injects a malicious code (shellcode) in the stack buffer. Such shellcode is a string of hexadecimal characters that correspond to instruction opcodes that can be executed by a processor. When executed, the main purpose of shellcode is to manipulate registers, functions, or syscalls of a program (originally, the term shellcode was derived from the action of spawning a root shell when executed on a target). Then, the attacker exploits the out-of-bound vulnerability (1) to overwrite the "vuln" return address in memory and replace it with the address of the buffer which contains the shellcode (2).

Figure 1.6: Stack-based buffer overflow exploit

As a result, when the "vuln" function returns, its return address is popped from the top of the stack to the program counter register that points on the next instruction to execute. Consequently, instead of returning to the "main" function, the "vuln" function returns to the shellcode previously injected by the attacker (2). Finally, the behavior of the target application is controlled by the injected shellcode.

Code injection attacks were very popular around the 2000s on desktops computers.

For instance, the SQL Slammer worm [START_REF] Lad | Analysis of bgp update surge during slammer worm attack[END_REF] was exploiting a buffer overflow in Microsoft's SQL servers to infect computers. Likewise, the Morris worm [START_REF] Orman | The morris worm: A fifteen-year perspective[END_REF] exploited a vulnerability in the Fingerd protocol to spread over the network and paralyze hundreds of thousands of computers.

Exploitation Techniques

Since then, several countermeasures have been proposed to protect applications against memory safety exploits. Three very famous buffer overrun protections such as Address Space Layout Randomization (ASLR) [START_REF] Shacham | On the Effectiveness of Address-Space Randomization[END_REF], Data Execution Prevention (DEP), and Stack Smashing Protector [START_REF] Wagle | Stackguard: Simple stack smash protection for gcc[END_REF] are currently widely deployed in most personal computer application. These countermeasures are summarized in Figure 1.7.

Figure 1.7: Common exploits mitigations

The Address Space Layout Randomization (ASLR) is managed by a classic operating system such as Linux or Windows. It has the effect of placing the stack at different memory offset (1) each time an application is executed. As a result, it is much more difficult for an attacker to predict the address of an injected malicious code in randomized memory areas. To push it further, various types of ASLR are currently available and deeply exposed hereafter.

The Data Execution Prevention (DEP) is a hardware feature that can be managed by operating systems with MMU and/or MPU support. The main purpose of DEP is to define non-code memory regions as not executable. Consequently, any malicious code injected into the stack, in particular, will no longer be treated as instructions.

The Stack Smashing Protector (SSP) is a compiler feature that requires a Random Number (RN). This feature enforces the return address protection of function that manages stack frame objects subject to overflow issues. Each time an application is executed, a random value is placed in a function's stack frame between the return address and the local variables [START_REF] Chiang | Fog and IoT: An Overview of Research Opportunities[END_REF]. Then, before a function returns, the value of the Stack Protector is checked to ensure that no out-of-bounds write modified the return address.

With the ASLR, DEP, and the SSP, memory corruptions are much harder to exploit on desktop computers. However, there are imperfect. For instance, the ASLR applies to both 32-bit and 64-bit systems. Regarding 32 bits systems, the entropy of the ASLR is very low (up to 8 bits). This means that a maliciously injected code position can be brute-forced in a reasonable time. Also, there is a downside to using canaries. At first, the compiler does not instrument all functions (around 20,5% functions for the Linux kernel [START_REF] Edge | Strong stack protection for gcc[END_REF]), so some of them remain unprotected. Besides, checking a canary value for each protected function introduce extra code that often results in performance degradation.

Chapter 1. Background Finally, DEP prevents attackers from executing malicious code in the data memory areas.

Although DEP is effective against code injection attacks, new attacks such as code-reuse attacks [START_REF] Checkoway | Return-oriented programming without returns[END_REF] completely overcome it.

Regarding embedded systems, it seems that the ASLR, DEP, and the SSP are not well-suited. Unlike desktop computers, embedded systems do not always benefit from an operating system with full MMU support nor Truly-/Pseudo-Random Generators [START_REF] Abbasi | Challenges in designing exploit mitigations for deeply embedded systems[END_REF].

Hence, embedded applications cannot be effectively protected by the ASLR and the SSP.

On top of that, many embedded systems are based on 32 bits' microcontroller systems.

As previously discussed, the 32 bits ASLR is weak. Finally, some embedded systems with a Memory Protection Unit [START_REF] Zhou | Good motive but bad design: Why ARM MPU has become an outcast in embedded systems[END_REF] (MPU) can define non-executable memory regions to thwart data-execution. However, the MPU does not enforce DEP by default on major embedded systems [START_REF] Abbasi | Challenges in designing exploit mitigations for deeply embedded systems[END_REF]. The configuration of the latter is left to developers, a task that is not always trivial. As a consequence, classical defenses against code injections are very limited when applied to embedded systems. It is therefore currently still easy to exploit software vulnerabilities on embedded systems using simple code injections [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF]37,[START_REF] Francillon | Code Injection Attacks on Harvard-Architecture Devices[END_REF]. An exploit technique called Return-to-Libc [START_REF] Tran | On the Expressiveness of Return-into-libc Attacks[END_REF] uses the presented scheme to bypass DEP. The main purpose of the Return-to-Libc attack is to gain execution-flow and chain multiple returns on security-critical functions located in the application libraries. Of course, the purpose of these attacks is to force an application to execute malicious actions.

Code-reuse attacks

Many "return-into" attacks such as [START_REF] Nergal | The advanced return-into-lib(c) exploits (PaX case study)[END_REF] have been inspired by the Return-to-Libc scheme.

However, "return-into" attacks suffer from minor limitations. Indeed, such an attack reuse functions that are part of the program or its libraries. Thus, an attacker may not find the functions he wants to execute his payload. Besides, for embedded systems that rely on a complex operating system such as Linux, the loaded shared libraries are often located in an executable area of the stack. Consequently, due to the Address Space Randomization (ASLR), the position of function libraries may change over time limiting the capabilities of exploits. Finally, bare-metal systems use statically linked libraries. It is frequent that compilers embed whole libraries without removing dead code, giving leeway to the attacker to build a working payload.

To circumvent the limitation of "ret-into" attacks, S. Krahmer introduced a new exploit technique [START_REF] Krahmer | x86-64 buffer overflow exploits and the borrowed code chunks exploitation technique[END_REF] which consists of redirecting the execution flow of a program on short sequences of instructions instead of functions. Later, this innovative exploit technique is generalized by Shacham [START_REF] Checkoway | Return-oriented programming without returns[END_REF] into the so-called Return-Oriented Programming (ROP) attack. The main purpose of ROP attacks is to divert the execution-flow of a target application on a short sequence of instructions that end with an indirect branch. These short sequences are called "gadgets" and are located in the code of the application itself.

The general idea is to make an application executing a gadget and use the branch at the end of the instruction sequence to transfer the execution-flow on another gadget. Consequently, given a large application with many instructions, an attacker may find enough gadgets to mount a Turing-complete language. By using this language, the attacker may be able to make the application successfully executes any malicious action he wants. It worth mentioning that the term Return-Oriented Programming comes from the fact that the first attacks used gadgets ending with a "ret" instruction. This instruction allows popping the top of the stack in the program counter register and transfers the control-flow to another gadget. An overview of a ROP attack is represented in Figure 1.9.

First, an attacker exploits a vulnerable buffer (stack-based in Figure 1.9). Then, the attacker injects a sequence of pointers (1), (2), (3). In Figure 1.9, this sequence first overwrites the return address of the vulnerable function (1) on other data higher up in the stack (2)(3). These pointers dereference gadgets located in the text section of the program. When the vulnerable function returns, the execution-flow of the application is redirected to the address pointed by the first gadget pointer (1). Then, when the first gadget returns, it transfers the execution to the next gadget (2) higher up in the stack using a "branch" [START_REF] Bletsch | Jump-Oriented Programming : A New Class of Code-Reuse Attack[END_REF][START_REF] Buchanan | When Good Instructions Go Bad : Generalizing Return-Oriented Programming to RISC[END_REF] or "ret" instruction. Finally, the process is repeated for (3), as well as all gadget addresses potentially injected by an attacker. In conclusion, by chaining Chapter 1. Background Figure 1.9: Return-Oriented Programming attack gadgets into a so-called "ROPchain" an attacker can trigger any arbitrary code execution.

Although the return-oriented programming attack was initially introduced on the x86 architecture [START_REF] Checkoway | Return-oriented programming without returns[END_REF], the technique has been quickly extended by researchers to target many other architectures such as ARM [START_REF] Checkoway | Return-oriented programming without returns[END_REF], SPARC [START_REF] Buchanan | When Good Instructions Go Bad : Generalizing Return-Oriented Programming to RISC[END_REF], Atmel [START_REF] Francillon | Code Injection Attacks on Harvard-Architecture Devices[END_REF], PowerPC [START_REF] Lindner | Cisco IOS Router Exploitation[END_REF] that are widely used in embedded systems. As a result, small Internet of Things devices based on exotic architectures are no exception to code-reuse attacks.

The major issue with code-reuse attacks and ROP, in particular, is that it overcomes the common protections against code injection attacks (ASLR, DEP, SSP). First of all, ROP is based on gadgets found in the executable text section of a program. Thus, no malicious code is executed on the stack bypassing the DEP protection. Secondly, many systems only benefit from a partial ASLR. This means that the text sections of programs are fixed from one application run to the next. As a direct consequence, the position of the gadgets in memory is fixed, allowing adversaries to deploy large scale exploits. Concerning systems that benefit from the full ASLR (randomization of the entire memory space of an application), it is often found that vulnerability is associated with a memory disclosure [42]. From this memory leak, an attacker can derandomize the vulnerable application memory layout and therefore, compute on-the-fly-all the memory addresses of the gadgets to achieve a successful attack [42]. It is worth reminding here that all embedded systems do not benefit from ASLR. Therefore, these systems are even weaker at mitigating ROP attacks. Finally, under certain conditions, A. Bittau et al. [START_REF] Tran | On the Expressiveness of Return-into-libc Attacks[END_REF] demonstrated through the blind Return-Oriented Programming technique that the stack canary can be bruteforced. The blind return-oriented programming attack works particularly well against an application that handles several processes. According to [START_REF] Tran | On the Expressiveness of Return-into-libc Attacks[END_REF], the crash of a process does not always cause the crash of the whole application as well as a reset of the canary value.

As a result, if the vulnerable process restarts, it is, therefore, possible to replay the exploit several times and brute force the canary value byte by byte. While this technique is noisy, 1.2. Exploitation Techniques it demonstrates the non-infallibility of stack canaries. Of course, the protection offered by a stack canary requires the support of a TRNG/PRNG [START_REF] Francillon | Tinyrng: A cryptographic random number generator for wireless sensors network nodes[END_REF] which is not always acquired for embedded systems [START_REF] Abbasi | Challenges in designing exploit mitigations for deeply embedded systems[END_REF].

That concludes the discussion on code-reuse attacks. Of course, this section does not tackle all the advanced exploitation techniques in the literature. They would be exposed when evaluating the state-of-the-art of existing memory safety defenses.

Data-oriented attacks

This section introduces the data-oriented programming attacks, a powerful class of attacks that exploits memory vulnerabilities to modify the behavior of an application without violating its control-flow graph. Indeed, diverting the control-flow graph is not the only way to achieve a successful attack. Usually, an attacker aims at modifying the behavior of an application to unlock security restrictions or gain more control. Consider, for instance, the code snippet with its the control-flow graph in Figure 1.10.

Figure 1.10: Data-oriented attack

There is an obvious out-of-bound vulnerability in (1). Also, the "vuln_function" is calling both the "priv" or the "unpriv" according to the providing password. The token variable is placed in the stack memory, very closed to the vulnerable buffer. As a result, an attacker can maliciously set the token variable to zero by exploiting the spatial vulnerability in (1). Of course, in this case, the comparison in (2) may fail. However, as the token has been maliciously set to one in (1), the comparison in (3) succeeds allowing the attacker to reach the privileged function. The important point is that a successful attack can be achieved without necessarily violating the control graph. Besides, dataoriented attacks such as the one presented in Figure 1.10 are very silent. They don't induce unexpected control-flow path and they can be very effective just by modifying a couple of bytes in memory.

In their paper, S. Chen et al. [START_REF] Chen | Non-Control-Data Attacks Are Realistic Threats[END_REF] demonstrated that data flow attacks targeting security-critical non-control data are realistic. Through their work, they identified many Chapter 1. Background security-critical data in real-world software that can be tampered resulting in compromises equivalent to control-flow attacks. According to [START_REF] Chen | Non-Control-Data Attacks Are Realistic Threats[END_REF] this critical data includes configuration data, user input, user identity data, and decision making data such as in Figure 1.10.

In the case of an insulin pump, the amount of medication to be delivered to a patient is critical data.

According to the previous description, it seems that the expressiveness of data-oriented attacks is more limited than control-flow attacks. However, H. Hu and al. [START_REF] Hu | Data-Oriented Programming : On the Expressiveness of Non-Control Data Attacks[END_REF] demonstrated that data flow attacks are Turing-complete. They introduced a generic exploitation method called data-oriented programming. This technique requires two elements: data-oriented gadgets and a gadget dispatcher. Data-oriented gadgets are sequences of instructions that manipulate and perform operations between registers and either load or store their results in/from the memory. These gadgets should respect the control-flow graph of the program and operate on data location controlled by an attacker thanks to a memory error. The purpose of the gadget dispatcher is to connect the data-oriented gadgets. To achieve this, the gadget dispatcher is composed of both a loop and a selector.

At each loop turn, the selector is used by the attacker to select and activate gadgets that perform operations on the data. Thus by chaining several loops and activating different gadgets, [START_REF] Hu | Data-Oriented Programming : On the Expressiveness of Non-Control Data Attacks[END_REF] demonstrated that they could build a Turing complete language allowing them to perform any operation on any data in memory. According to their results, 8 out of 9 real-world programs contained data-oriented gadgets, and 2 were fully exploitable using data-oriented programming. These results demonstrate that attacks on data flow becomes increasingly practicable and empower more and more attackers.

So far, data-oriented attacks [START_REF] Chen | Non-Control-Data Attacks Are Realistic Threats[END_REF][START_REF] Evans | Control Jujutsu : On the Weaknesses of Fine-Grained Control Flow Integrity[END_REF][START_REF] Sun | The power of data-oriented attacks: Bypassing memory mitigation using data-only exploitation[END_REF] are powerful enough to bypass DEP, ASLR, and SSP. Protecting systems against data flow attacks is thus a complex problem. First, dataoriented attacks do not violate the control-flow graph of an application. Consequently, it is difficult to distinguish legitimate access to resources from illegitimate ones. Then, as applications are becoming increasingly complex, the amount of critical data increases proportionally. For performance reasons, it is impractical to protect every critical data within an application. Finally, during the software development phase of a program, it is extremely difficult to determine which data is critical or not. Some data may appear noncritical, however, in the hands of an attacker, it can become devastating. According to [START_REF] Hu | Data-Oriented Programming : On the Expressiveness of Non-Control Data Attacks[END_REF] it seems that a simple loop iteration data can be reused for malicious purposes. Nowadays, most of the countermeasures against data-oriented attacks are still at the research stage and are discussed later in this thesis.

Real-world exploits

The preceding sections highlight the various techniques used by attackers to hijack a vulnerable program. While several exploit examples were given, it is not discussed whether control-flow or data-oriented attacks have already been applied to critical medical devices. Also, do these exploits exist in the wild on real applications? Which exploit technique is the most commonly used? The purpose of this section is to demonstrate that medical devices are no exception to memory vulnerabilities. Unfortunately, threats such as attacks 1.2. Exploitation Techniques on control-flow or security-critical data are awfully real on critical medical devices. Recent research on Smiths Medical Medfusion 4000 pumps [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF] has uncovered several stack buffer overflows in the real-time operating system of the device. Such critical vulnerabilities allow an attacker to remotely take control of the pump. This research uncovered an embedded system that does not benefit from the ASLR, DEP, and SSP. As a result, a successful complete exploit is achieved with a simple code injection attack. This vulnerability also underlines what was previously exposed in section 1.1. Indeed, the root cause of the vulnerability is the use of a third-party real-time system, itself having a certain complexity and a consequent number of lines of code. It must be stressed that this example of memory corruption is only one among others. By digging on different Common Vulnerability Exposure (CVE) databases it is straightforward to find many critical vulnerabilities on medical systems [15,[START_REF]Hospira Multiple Products Buffer Overflow Vulnerability[END_REF][START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF]. Another important point is that the exploitation techniques explained in the previous sections are very categorical. In reality, the exploitation techniques of the attackers are hybrid. Real-world exploits combine code-reuse, code injection, and data-oriented attacks to bypass the defenses of a device. For instance, in the presence of an extremely protected system, an attacker tends to combine techniques such as codereuse, and/or data-oriented programming to first overcome the system protections such as DEP. Then, in a second time, the attacker performs a code injection attack to execute its malicious shellcode.

Studying the life cycle of an exploit makes it possible to realize the importance of memory-based defenses. According to [START_REF] Ablon | Zero days, thousands of nights: The life and times of zero-day vulnerabilities and their exploits[END_REF], after being discovered, an exploit has a lifespan of 6.9 years. This means that even if a patch is released by manufacturers, many systems are never updated and remain exposed to security threats. Furthermore, after a critical vulnerability discovery, it takes an average of 22 days for hackers to develop a working exploit [START_REF] Ablon | Zero days, thousands of nights: The life and times of zero-day vulnerabilities and their exploits[END_REF]. This means that attackers are moving fast. Consequently, the current memory-based defenses can be significantly improved to decrease the criticality of vulnerabilities and increase the development time of working attacks. Finally, according to [START_REF] Ablon | Zero days, thousands of nights: The life and times of zero-day vulnerabilities and their exploits[END_REF], "given stockpile of zero-day vulnerabilities, after a year approximately 5.7 percent have been discovered and disclosed". This underlines that many vulnerabilities are currently not public and work in the shadow threatening all types of systems. It is, therefore, necessary to innovate in defense mechanisms to break functional exploits techniques and harden embedded systems software as much as possible to face the next Internet of Things era.

Chapter 1. Background

Existing Defenses

The previous section outlined an overview of memory-based attacks. Awareness of attacks is worthwhile to design and understand efficient defenses. In this section, the state-of-the-art regarding advanced defenses against software attacks is exposed. Through this study, new advanced attacks are also presented and complement the ones discussed in the previous section. Indeed, with the advent of new countermeasures, innovative and more robust attacks are constantly developed. behavior can be suspected. Randomization may also be an efficient method to prevent code-reuse attacks. Following this idea, each application has the same high-level code but different low-level instructions. Consequently, a working exploit on an application may be difficult to deploy at scale. Finally, it seems that defenses based on data integrity are much harder to design when thinking in terms of control-flow graphs. A concept that would probably reduce data-oriented attacks would be to monitor critical data integrity As this work targets critical embedded systems, the following state-of-the-art gives more importance to hardware/software co-design countermeasures. However, this work also gives credit to the defenses implemented on desktop computers. In the end, all the concepts are compared with each other to expose the gap regarding life-critical systems defenses and our approach.

Control-flow integrity

Control-flow integrity is a practical defense introduced by M. Abadi [START_REF] Abadi | Control-Flow Integrity Principles, Implementations, Applications[END_REF] to mitigate control-flow attacks. Control-flow integrity ensures that an executed path in a program always complies with the original static control-flow graph. Figure 1.12 displays a controlflow graph where each indirect transition in the graph is checked to ensure that a legitimate path is taken. There are several ways to implement control-flow integrity providing both a different policy and a different accuracy. Some existing implementations are backward-edge oriented. This means that the control-flow integrity policy guarantees that all backward-edges are always reaching a valid destination. Conversely, there are control-flow integrity policies that ensure that all forward-edges always reach a valid vertex (forward-edge control-flow integrity). Of course, the combination of the two equally exists and provides a much more complete defense. The accuracy of a control-flow integrity solution is defined by the number of valid destinations a branch can reach. For instance, in Figure 1.12, it appears that vertex 6 can either return in vertex 4 or vertex 5.

Figure 1.12: Control-flow integrity

A fine-grained control-flow integrity solution ensures that the vertex 6 returns to its more recent calling vertex. On the other hand, a coarse-grained control-flow integrity solution only ensures that the vertex 6 returns to one of the two vertices which are 5 Chapter 1. Background or 4. Although coarse-grained control-flow integrity is less accurate than fine-grained control-flow integrity, it still degrades a wide range of control-flow attacks. However, it does not prevent an adversary from slightly modifying the program execution flow without breaking the control-flow graph. There is a metric titled Average Indirect target Reduction (AIR), introduced by bin-CFI [START_REF] Zhang | Control flow integrity for cots binaries[END_REF]. This metric is commonly used to evaluate control-flow integrity accuracy. The AIR is given by the formula 1.1:

AIR = 1 n n j=0 (1 - T j S ) (1.1)
Where n is the number of indirect control-flow transfer in a program, S the total number of target addresses that can be reached by a branch (it is the size of the binary).

T j represents the number of addresses that can be reached by a transfer j restricted by control-flow integrity protection. It seems that if the percentage given by this formula is close to 99% the control-flow solution can be considered as fine-grained [START_REF] Walls | Control-flow integrity for real-time embedded systems[END_REF]. Conversely, a very coarse-grained control-flow protection has an AIR close to 80% [START_REF] Walls | Control-flow integrity for real-time embedded systems[END_REF].

Label-based control-flow integrity

One solution to achieve control-flow integrity is to use immutable code labels [START_REF] Abadi | Control-Flow Integrity Principles, Implementations, Applications[END_REF][START_REF] De Clercq | A survey of Hardware-based Control Flow Integrity (CFI)[END_REF] This means that the labels are inserted after a call instruction on the top of a basic block of code. It worth mentioning that labels maybe just regular 32 bits memory words.

The control-integrity solution works as follows, when a function returns to its caller, the destination label of the return site is checked to ensure that the application is following a legitimate path. For instance, when function B returns, it checks that the preceding location of the return site contains the correct label.

At first glance, such a principle defeats a wide range of control-flow based attacks exposed in the previous sections. However, Figure 1 As previously discussed, some functions share the same label ID. Unfortunately, it relaxes the accuracy of the control-flow integrity policy as some function can return to multiple callers. One of the positive points of label protections is that the labels are fixed and not modifiable by the attacker thanks to the immutability of the code. Thus, an attacker can neither modify a label nor inject code with a new label in the application data space. On the other hand, label-based control-flow integrity protection does not prevent an attacker from achieving an attack that remains within the control-flow graph enforced by the labels. This well-known attack, titled call-preceded [START_REF] Carlini | ROP is Still Dangerous : Breaking Modern Defenses[END_REF] return-oriented programming leverage the label-based control-flow graph to achieve malicious code execution.

In their paper, M. Abadi and al. [START_REF] Abadi | Control-Flow Integrity Principles, Implementations, Applications[END_REF] implemented an inline label-based control-flow integrity protection for Windows applications. They analyzed all indirect control-flow transfers in various applications. Then, they instrumented them with unique labels using Vulcan [START_REF] Edwards | Vulcan binary transformation in a distributed environment[END_REF] a binary rewriter framework. They demonstrated that label-based control-flow integrity is easily portable and can be compliant with formal analysis methods. However, their control-low integrity implementation induces a run-time overhead up to 45% on the SPEC2000 [START_REF] Henning | SPEC CPU2000: Measuring cpu performance in the new millennium[END_REF] benchmark suite. Applied to embedded systems such a pure software label-based control-flow integrity is excessively costly regarding real-time performances.

Finally, control-flow integrity introduced by M. Abadi and al. [START_REF] Abadi | Control-Flow Integrity Principles, Implementations, Applications[END_REF] is coarse-grained and Chapter 1. Background vulnerable to [START_REF] Carlini | ROP is Still Dangerous : Breaking Modern Defenses[END_REF].

Label-based control-flow integrity takeaways

• Label-based control-flow integrity identifies each vertex in a control-flow graph with a unique label.

• Labels are protected by the immutability of the code. They restrict the control-flow of a program to its static control-flow graph.

• Pure software label-based control-flow integrity is coarse-grained and may induce execution-time overhead up to 46% [START_REF] Abadi | Control-Flow Integrity Principles, Implementations, Applications[END_REF].

Shadow call stack-based control-flow integrity

To overcome the label limitation, M.Abadi et al. [START_REF] Abadi | Control-Flow Integrity Principles, Implementations, Applications[END_REF] suggested the use of a shadow call stack. A shadow call stack handles copies of return addresses at run-time. Usually, a shadow call stack is composed of two elements, a hardware or software buffer and a controller. The hardware/software buffer is an isolated memory area that cannot be tampered by a memory-based attack. This buffer is driven by a logic component called a controller. The main purpose of the controller is to manage the state of the buffer (if it is full or not) and the requests made by the secured software. During execution, each function call and return make a query to the controller of the shadow call stack. More specifically, Figure 1.14 displays the functioning of a shadow call stack.

Figure 1.14: Shadow call stack

When a function call occurs, for instance, from vertex 2 to vertex 3, the vertex 3 return address is pushed both in the regular stack and in the memory buffer of the shadow call stack. When the vertex 3 returns, the return address on the top of the stack is used to return to the caller routine. Synchronously, the top return address of the stack is checked using the top address of the shadow stack (displayed using a xor in Figure 1.14). In case of a mismatch, the program ends with an error. Otherwise, the return address is popped 1.3. Existing Defenses from both stacks. In Figure 1.14, the shadow call stack provides a fine-grained backwardedge control-flow integrity protection. As mentioned by [START_REF] Abadi | Control-Flow Integrity Principles, Implementations, Applications[END_REF] the shadow call stack ensures that a vertex is always returning to its most recent caller.

Many hardware designs that implement various shadow call stacks have been proposed

in the literature to protect embedded systems [START_REF]Control-flow Enforcement Technology Specification[END_REF][START_REF] Sullivan | Strategy Without Tactics : Policy-Agnostic Hardware-Enhanced Control-Flow Integrity[END_REF][START_REF] Davi | MoCFI: A framework to mitigate control-flow attacks on smartphones[END_REF][START_REF] Christoulakis | HCFI : Hardware-enforced Control-Flow Integrity[END_REF][START_REF] Alam | SmashClean : A Hardware level mitigation to stack smashing attacks in OpenRISC[END_REF][START_REF] Kayaalp | Efficiently Securing Systems from Code Reuse Attacks[END_REF]. One of the most recurring issues faced by shadow call stack designers is defining the size of the memory buffer. While hardware shadow stacks induce low execution-time overhead, the cost of an additional on-chip hardware memory can be increasingly high. Also, a shadow call stack can only contain a limited number of entries. Thus, if an application call-depth is higher than the size of the shadow stack, an overflow may happen. One solution to tackle this issue is to design a shadow call stack with a capacity that supports the maximum call depth of a wide range of applications. However, this proposition faces several limitations. First of all, a recursive call sequence with unfixed boundaries may tend to overflow the shadow call stack. Secondly, it is hard to set a shadow call stack size that may be suitable for every existing application. It follows that to be properly used, shadow call stacks must be accompanied by programming rules as well as tools to formally verify that software may not produce a shadow-stack overflow.

To overcome the size limitation, [START_REF] Vijaykumar | SmashGuard : A Hardware Solution to Prevent Security Attacks on the Function Return Address[END_REF] proposed an interruption routine that regularly checks the stack capacity and moves the oldest return addresses to a secure memory space.

Following the same idea, the NSA [START_REF] Davi | MoCFI: A framework to mitigate control-flow attacks on smartphones[END_REF] proposed a flexible shadow call stack based on the Memory Management Unit. Unfortunately, shadow call stacks have other limitations such as multi-tasks programs. To manage a stack checking coherency in a multi-tasks application, a shadow stack should be managed for each independent task. This type of management is difficult to achieve for pure-hardware shadow call stacks. The proper way to implement it is to assist the hardware shadow call stack with a kernel that restores the appropriate shadow call stacks during context switching.

Another issue is that shadow stacks are not compliant with all possible constructions offered by the C language. One of the well-known issues is the use of "setjmp/longjmp" functions. These functions provide a way to perform inter-procedural jumps in an application breaking the standard call/return sequence. Although their use is prohibited in critical applications, it is not uncommon for them to be used to handle exceptions. Unfortunately, after a "longjmp" the address on the top of the shadow stack no longer matches the return address of the regular call stack. As a result, this mismatch may induce false control-flow violations.

To support the "setjmp/longjmp" issue, some advanced shadow call stack leverage open-hardware architectures with additional instructions and registers. For instance, HCFI [START_REF] Christoulakis | HCFI : Hardware-enforced Control-Flow Integrity[END_REF] modifies the SPARC architecture to enforce both backward and forward-edge control-flow integrity. HCFI introduces 6 customs instructions to the SPARC architecture.

Among these 6 instructions, 2 instructions (SJCFI and LJCFI) are specifically dedicated to the "setjmp/longjmp" issue. The SJCFI instruction is placed just after a "setjmp" function call and carries a unique label that is part of its 8 least significant bits. In addition to holding a label, the SJCFI instruction serves as the landing point for the "longjmp"

Chapter 1. Background function. When the "setjmp" function returns, the SJCFI instruction is executed. This has the effect of saving the index of the top of the shadow stack in an isolated memory indexed by the label of the instruction. Likewise, the LJCFI instruction is placed after a "longjmp" function. Once executed, the execution flow is redirected back on the SJCFI instruction (which is the restoration point of the "setjmp/longjmp" procedure). Then, the second feature of the SJCFI instruction is activated. This instruction allows the hardware logic to read the index of the previously saved top shadow stack and restore it.

HCFI [START_REF] Christoulakis | HCFI : Hardware-enforced Control-Flow Integrity[END_REF] is dedicated to bare-metal applications. To benefit from the hardware security feature, an application has to be compiled in an assembly file first. This assembly file is then instrumented using python script [START_REF] Christoulakis | HCFI : Hardware-enforced Control-Flow Integrity[END_REF] to be finally compiled into a binary. While this process is scalable to test small applications, it is difficult to deploy in a production environment. The compilation process is heavy. It requires several steps to generate a final binary. In terms of security, [START_REF] Davi | Hafix: Hardware-assisted flow integrity extension[END_REF] defeats most of the return-oriented programming attacks ensuring a fine-grained backward-edge control-flow integrity. [START_REF] Davi | Hafix: Hardware-assisted flow integrity extension[END_REF] also ensures forward-edge control-flow integrity through labels. The implementation relies on the point-to analysis performed at compilation time. Finally, leveraging the hardware for software security support is a clever strategy to reduce the performance overhead. For instance, HCFI induces less than of 1% execution-time penalty on average.

To deal with the recursion issue, Davi et al. proposed HAFIX [START_REF] Davi | Hafix: Hardware-assisted flow integrity extension[END_REF] an architecture that ensures a fine-grained backward-edge control-flow integrity based on hardware labels.

HAFIX extends the Intel Siskiyou Peak architecture with four instructions and an isolated memory area to achieve control-flow integrity. Each application running on HAFIX is instrumented such that every function begins with a CFIBR instruction, each call instruction in a program is followed by a CFIRET instruction, and each return instruction is preceded by a CFIDEL instruction. As a result, each time a function is called, the CFIBR is executed by the processor. This instruction active a unique function label in an isolated memory area. When the function terminates, the CFIDEL instruction is executed before the return instruction. This has the effect of deactivating the label from the trusted memory. Then, the function returns to the CFIRET instruction placed after the call instruction of the caller. This instruction contains the label of the caller function and makes the hardware checking that this function is enabled.

HAFIX tackles recursion by using additional CFIREC instruction. As the CFIBR instruction, the CFIREC is placed at the beginning of a recursive function. Once executed by the processor, CFIREC enables the label of the recursive function. This instruction is linked with a specific CFIREC_CNTR register. Every time the recursive function is called, the CFIREC_CNTR register is incremented. Once the recursive function returns, the processor checks if the function's label is enabled and if the CFIREC_CNTR register is greater than 1. If both conditions are verified, the CFIREC_CNTR register is decremented. Otherwise, the recursion is over and the label is deactivated. In comparison with HCFI [START_REF] Christoulakis | HCFI : Hardware-enforced Control-Flow Integrity[END_REF], HAFIX does not ensure forward-edge control-flow integrity. Also, a return instruction can always return to an active site that is not the most recent caller of a function.

Indeed, HAFIX does not prevent an attacker from returning in a caller's active function of 1.3. Existing Defenses its caller. Regarding the performance, HAFIX induces less than 2% execution-time overhead. Moreover, HAFIX comes with a compiler extension that automatically generates secure code with secure instructions. This approach is more practical to be deployed in software production environments than [START_REF] Christoulakis | HCFI : Hardware-enforced Control-Flow Integrity[END_REF]. It allows error-free security integration for non-security experts.

The key point of this section is that shadow stacks are efficient at providing finegrained backward-edge control-flow integrity. In other words, a shadow stack can be assimilated into a simple redundancy mechanism for functions' return address. However, this section also reveals that shadow stacks come with several limitations such as the size, the recursion, the way C structures such as "setjmp/longjmp" are managed and multitasks applications.

Shadow stacks takeaways

• Shadow stacks provide fine-grained backward-edge control-flow integrity.

• Shadow stacks require dedicated support for multi-tasks systems, recursion, and "setjmp/longjmp".

• The execution-time overhead induced by hardware shadow stacks is low.

Unfortunately, hardware shadow stacks are always limited by their size.

Chapter 1. Background

Branch policy-based control-flow integrity

The majority of control-flow attacks break the static control-flow graph of a program.

Code-injection attacks redirect the execution flow of an application on a malicious code located out of the control-flow graph. In contrast, code-reuse attacks divert the executionflow on several gadgets scattered in the code of a vulnerable program. Thus, monitoring any deviation from the original control-flow graph may be an effective process to catch control-flow based attacks. One way to detect control-flow violations is to monitor each indirect branch at run-time. Such a method, called "branch limitation" or "branch re- BB-CFI [START_REF] Das | A Fine-Grained Control Flow Integrity Approach Against Runtime Memory Attacks for Embedded Systems[END_REF] is an x86-based architecture with a branch restriction policy. BB-CFI uses a hardware control-flow checker to monitor the behavior of an application over time.

The control-flow check enforces that every jump instruction is restricted to the beginning of a basic block. Besides, the control-flow checker restricts every function call to the first basic block of a function. To be aware of each valid branch destination, the BB-CFI must be configured with a metadata file that contains the valid destination target of every branch. Of course, this configuration file is stored in secure memory so that it may not 1.3. Existing Defenses be tampered by any memory-based attacks. According to [START_REF] He | No-jump-into-basic-block: Enforce basic block CFI on the fly for real-world binaries[END_REF], BB-CFI can thwart every attack from the RIPE benchmark suite, providing fine-grained control-flow integrity.

To dispense with the use of a metadata file such as [START_REF] Das | A Fine-Grained Control Flow Integrity Approach Against Runtime Memory Attacks for Embedded Systems[END_REF] , W. He [START_REF] He | No-jump-into-basic-block: Enforce basic block CFI on the fly for real-world binaries[END_REF] proposes BBB-CFI a similar approach than [START_REF] Das | A Fine-Grained Control Flow Integrity Approach Against Runtime Memory Attacks for Embedded Systems[END_REF] . This proposal checks that the destination target of an indirect branch is preceded by a branch instruction. Indeed, since a branch instruction marks the end of a basic block and the beginning of a new one, checking the instruction preceding the jump target ensures whether the destination is the beginning of a basic block or not. Unfortunately, in the case of fall-through or switch, this policy doesn't work.

To overcome this exception, W. He [START_REF] He | No-jump-into-basic-block: Enforce basic block CFI on the fly for real-world binaries[END_REF] proposes a second rule in which a list of allowed branches not covered by the first rule is maintained and does not raise a control-flow exception. Like BB-CFI [START_REF] Das | A Fine-Grained Control Flow Integrity Approach Against Runtime Memory Attacks for Embedded Systems[END_REF], BBB-CFI [START_REF] He | No-jump-into-basic-block: Enforce basic block CFI on the fly for real-world binaries[END_REF] is implemented in hardware on an FPGA.

It consists of several components such as a control-flow checker that interacts with the pipeline of a processor. This control-flow checker itself contains two elements; shadow call stacks for backward-edges, and a checker module that enforces rules 1 and 2. More deeply, BBB-CFI uses a 32 entry shadow call stack, and the average amount of memory required to store the metadata file containing the second rule represents 13% of an application.

BBB-CFI also induces an overhead of 0.13% at runtime which is negligible. Finally, in terms of security BBB-CFI is confronted with the Benchmark-RIPE [START_REF] Wilander | RIPE: runtime intrusion prevention evaluator[END_REF] suite. All attacks of the suite are countered by BBB-CFI except the return-to-libc attacks.

Intel Control-Flow Enforcement Technology [START_REF]Control-flow Enforcement Technology Specification[END_REF] is similar to BBB-CFI. Indeed, it combines a hardware/software branch restriction policy for the forward-edges with a shadow call stack for the backward-edges. Indeed, Intel CET introduces a new ENDBANCH instruction in the x86 instruction set. The ENDBRANCH instruction is used to mark the beginning of a valid destination block for an indirect forward-edge. According to the specifications [START_REF] Walls | Control-flow integrity for real-time embedded systems[END_REF], the Intel x86 processor implements an additional finite state machine in the pipeline that tracks the indirect branches of an application. When a branch instruction passes through the pipeline, the state machine moves into a "WAIT_FOR_ ENDBRANCH" standby state. This state waits until the next instruction passing in the pipeline is an ENDBRANCH to confirm a valid branch destination. If an ENDBRANCH instruction is not seen by the processor, a control-flow exception is raised. Otherwise, the finished state machine returns to its initial "IDLE" state. Currently, no specific security assessment has been performed on Intel CET, according to [START_REF] De Clercq | A survey of Hardware-based Control Flow Integrity (CFI)[END_REF], Intel-CET being similar to [START_REF] He | No-jump-into-basic-block: Enforce basic block CFI on the fly for real-world binaries[END_REF] provides approximately the same security level.

While [START_REF]Control-flow Enforcement Technology Specification[END_REF][START_REF] Das | A Fine-Grained Control Flow Integrity Approach Against Runtime Memory Attacks for Embedded Systems[END_REF][START_REF] He | No-jump-into-basic-block: Enforce basic block CFI on the fly for real-world binaries[END_REF] prevents control-flow attacks by enforcing branch monitoring, C-FLAT [START_REF] Abera | C-FLAT: Control-FLow ATtestation for Embedded Systems Software[END_REF] proposes to measure the path taken by an application at runtime. To achieve path measurement, C-FLAT monitors every indirect branch operated at runtime and computes a cumulative hash using the source and the destination address of each taken branch. The whole mechanism works with a prover and a verifier. The prover runs on the system to be monitored and computes the cumulative hash of the paths taken by an application. Then, it sends the cumulative hash result to a remote verifier which checks that the hash is consistent with a list of pre-computed hashes. In case a cumulative hash does not find a match in the verifier hash database a control-flow violation is lifted. C-Chapter 1. Background FLAT is purely implemented in software and runs on the ARM architecture. Initially, the application which must be protected is instrumented thanks to a script. Each branch raises an interruption that transfers the execution to the prover. The latter computes the cumulative hash using the source and destination address of the jump. Finally, the prover returns the execution-flow to the main application and sends the cumulative hash value to the verifier. In C-FLAT, the prover is placed in an isolated memory (TrustZone [START_REF] Arm | Security technology building a secure system using trustzone technology[END_REF]), unattainable from the monitored main application memory. It follows that the prover is protected from the monitored application. According to [START_REF] Abera | C-FLAT: Control-FLow ATtestation for Embedded Systems Software[END_REF], C-FLAT is extremely accurate. Indeed, C-FLAT can also be used to monitor direct branches. Also, C-FLAT can detect non-control data attacks that target loops [START_REF] Hu | Data-Oriented Programming : On the Expressiveness of Non-Control Data Attacks[END_REF]. However, the accuracy of C-FLAT comes at a certain price. The performance of C-FLAT is measured on a realtime system such as the open-syringe [START_REF] Wijnen | Open-Source Syringe Pump Library[END_REF]. It turns out that when an application is not monitored by C-FLAT the execution overhead decreases from 72 to 80%. Also, according to [START_REF] Abera | C-FLAT: Control-FLow ATtestation for Embedded Systems Software[END_REF], the majority of the overhead induced by C-FLAT comes from the hash algorithm, from the switches between the TrustZone and the untrusted memory and, finally, from the interrupt of the measurement engine.

To improve C-FLAT [START_REF] Abera | C-FLAT: Control-FLow ATtestation for Embedded Systems Software[END_REF], Davi et al. proposed LO-FAT [START_REF] Dessouky | LO-FAT: Low-Overhead Control Flow ATtestation in Hardware[END_REF] an implementation of C-FLAT but at the hardware level. LO-FAT leverages the open-source RISC-V architecture [START_REF] Waterman | The risc-v instruction set manual; volume ii: Privileged architecture, sifive inc. and cs division, eecs department[END_REF] to implement the monitoring mechanism of C-FLAT. To monitor branches, LO-FAT is incorporated directly into the instruction pipeline of the RISC-V Pulpino processor [START_REF]Pulpino. An Open-Source Microcontroller System based on RISC-V[END_REF]. This strategy offers several advantages over C-FLAT. First, LO-FAT tracks branches directly at the hardware level without interrupting the software execution. Also, the hardware monitor of LO-FAT computes the cumulative hash in parallel with the application execution. Finally, the monitored application is not instrumented thanks to the branch monitor that recognizes branches in the processor pipeline.

In closing, LO-FAT takes advantage of hardware to fill the lack of C-FLAT. Regarding the security, LO-FAT [START_REF] Dessouky | LO-FAT: Low-Overhead Control Flow ATtestation in Hardware[END_REF] is as accurate as C-FLAT [START_REF] Abera | C-FLAT: Control-FLow ATtestation for Embedded Systems Software[END_REF]. To remind, both solutions are fine-grained and able to detect some advanced data-oriented attacks [START_REF] Hu | Data-Oriented Programming : On the Expressiveness of Non-Control Data Attacks[END_REF]. Unlike C-FLAT, the run-time overhead induced by LO-FAT is very low, less than 5%. Besides, LO-FAT increases the size of a RISC-V Pulpino processor by around 20%. Finally, one of the negative aspects of both solutions is that they do not prevent attacks, they can only observe them. Moreover, these solutions require maintaining a hash database which can be extremely heavy depending on the application to be monitored.

Branch policy takeaways

• Branch policies restrict or monitor the execution-flow according to the control-flow graph.

• Hardaware-based monitors usually induce a low execution-time overhead.

• Branch policies are useless against data-oriented attacks and attacks that remain within the control-flow graph. redirected on a trampoline routine. This trampoline performs an Address Translation of function pointers to compute an index in a table that corresponds to a valid destination target. Finally, the execution flow is redirected from the table entry which contains a jump to a valid final destination.

Many existing implementations use a trampoline approach to enforce a control-flow integrity [START_REF] Zhang | Control flow integrity for cots binaries[END_REF][START_REF] Davi | MoCFI: A framework to mitigate control-flow attacks on smartphones[END_REF][START_REF] Tice | Enforcing Forward-Edge Control-Flow Integrity in GCC & LLVM[END_REF][START_REF] Zhang | Practical Control Flow Integrity & Randomization for Binary Executables[END_REF]. However, among these implementations two categories of trampoline approaches may be discerned: those that protect a program at compile-time [START_REF] Tice | Enforcing Forward-Edge Control-Flow Integrity in GCC & LLVM[END_REF] and those that act after compilation [START_REF] Zhang | Control flow integrity for cots binaries[END_REF][START_REF] Davi | MoCFI: A framework to mitigate control-flow attacks on smartphones[END_REF][START_REF] Zhang | Practical Control Flow Integrity & Randomization for Binary Executables[END_REF], directly on a binary.

For instance, MoCFI [START_REF] Davi | MoCFI: A framework to mitigate control-flow attacks on smartphones[END_REF], CCFIR [START_REF] Zhang | Practical Control Flow Integrity & Randomization for Binary Executables[END_REF], and bin-CFI [START_REF] Zhang | Control flow integrity for cots binaries[END_REF] use a trampoline based approach applied after compilation to enforce both forward and backward-edge control-flow integrity. Both [START_REF] Zhang | Practical Control Flow Integrity & Randomization for Binary Executables[END_REF] and [START_REF] Zhang | Control flow integrity for cots binaries[END_REF] MoCFI [START_REF] Davi | MoCFI: A framework to mitigate control-flow attacks on smartphones[END_REF] follows the principle of both bin-CFI [START_REF] Zhang | Control flow integrity for cots binaries[END_REF] and CCFIR [START_REF] Zhang | Practical Control Flow Integrity & Randomization for Binary Executables[END_REF] Unfortunately, the trampoline approach enforced by binary rewriting has many limitations. Rewriting every indirect control-flow branch, adding trampolines and tables has the effect of increasing the size of the final binary. For instance, bin-CFI [START_REF] Zhang | Control flow integrity for cots binaries[END_REF] increases the average size of an executable by 139%. As a result, this type of solution may be acceptable for a desktop application with unlimited memory but unreasonable for a small embedded system. Second, the accuracy of the control-flow integrity protection is based on the accuracy of the control-flow graph computed by the static analyzer. Unfortunately, it is almost impossible to estimate an accurate control-flow graph by only using static analysis.

As a result, the instrumentation is often coarse-grained degrading the security. Another limitation is that trampoline approaches cannot protect embedded system interruptions/exceptions if not using a shadow call stack. Indeed, static binary rewriting techniques cannot predict wherein the code an interruption may be lifted. It follows that they also cannot determine their return location.

Finally, to enforce forward-edge control-flow integrity, Google Inc. [START_REF] Tice | Enforcing Forward-Edge Control-Flow Integrity in GCC & LLVM[END_REF] proposes to use trampoline instrumentation at compilation time. This approach is more compatible with software engineering concepts and can be easily integrated into a software development life-cycle. The general idea of their approach remains the same as for bin-CFI [START_REF] Zhang | Control flow integrity for cots binaries[END_REF] and MoCFI [START_REF] Davi | MoCFI: A framework to mitigate control-flow attacks on smartphones[END_REF] but is implemented in the GCC compiler as VTV [START_REF] Griffith | GCC: The Complete Reference[END_REF] and the LLVM [START_REF] Lattner | LLVM: A compilation framework for lifelong program analysis & transformation[END_REF] compiler as IFCC. The main asset of using a compiler is that more high-level information is present in the program during the compilation phase and therefore it is much easier to determine the indirect control-flow transfers of an application. Also, the compilation phase 1.3. Existing Defenses allows optimizing the trampoline routine implementation for each indirect branch. To assess the security level of their protection, [START_REF] Dessouky | LO-FAT: Low-Overhead Control Flow ATtestation in Hardware[END_REF] introduces the concept fAIR (forward-edge Average Indirect target Reduction), which evaluates the quality of control-flow integrity protection by only taking into account the forward-edges. They measured an average of 99.8% fAIR with a performance penalty ranging from 0.6-5.8% for the SPEC 2006 C++ benchmark.

Trampoline control-flow integrity takeaways

• Trampoline control-flow integrity redirects indirect control-flow transfer on trampoline routines that checks their destination target.

• Trampoline solutions are mostly implemented in software, and some of them require the binary rewriting techniques.

• Most binary rewriting techniques are coarse-grained and induce nonnegligible size overhead.

Heuristic defenses

Like current anti-virus software that detects the presence of malware on systems, heuristic analysis can also be applied to detect control-flow attack signatures. The main purpose of the heuristic analysis is to track a program at run-time and recognize suspicious behaviors that look like a code-reuse or a code injection attack. To be accurate, the heuristic analysis requires a set of specific signatures that allows it to assess the risk of a system being under attack. These signatures are determined from the knowledge of control-flow exploits patterns. For instance, Figure 1.17 displays a Return-Oriented Programming attack on the right. On the left, one can observe a list of gadgets (short sequences of instructions that end with a branch) that are scattered in the "text" section address space of the application. These gadgets can be extracted using custom tools such as ROPgadget [START_REF] Salwan | ROPgadget[END_REF].

Figure 1.17: ROP signature

In Figure 1.17, some specific code-reuse attack characteristics can be extracted. On the left, it appears that the majority of code reuse attacks use gadgets which are small sequences of instructions (between 1 and 6) ending with an indirect branch. It turns out that the average number of instructions executed between two branches is very low, which is rarely the case in a normal application. Thus, one common signature of code-reuse attacks is a low ratio of instructions between branches. On the right of Figure 1.17, the system under attack is performing a lot of jumps all over the text section in a short period.

Thus, a second signature specific to code-reuse attacks is the high ratio of branches over a short time window.

For hardware processor architectures that benefit from a speculative branching unit, code-reuse attacks induce a lot of address misprediction [START_REF] Polychronakis | ROP Payload Detection Using Speculative Code Execution[END_REF]. For instance, a prediction unit such as the Return Address Stack (RAS) cannot predict the destination address of a return in a code-reuse attack because the happening returns are not associated with call [START_REF] Wang | SIGDROP : Signature-based ROP Detection using Hardware Performance Counters[END_REF]. Thus a high level of branches misprediction is a signature of code-reuse attacks.

Finally, one of the commonalities of return-into-libc attacks is that they try to execute a 1.3. Existing Defenses system call or a sensitive function. As a result, the use of one or more sensitive system calls in a non-regular way may also be a sign of an attack.

In summary, by looking for signatures such as the number of consecutive indirect branches, the number of instructions between two branches, the number of branches over a short time window, the misprediction rate of a speculative unit and, the use of system calls, it is possible to determine whether a system is likely to be attacked.

kBouncer [START_REF] Pappas | kbouncer: Efficient and transparent rop mitigation[END_REF] is a heuristic engine implemented in Windows that leverages the use of dangerous function/system calls to detect return-oriented programming attacks. kBouncer [START_REF] Pappas | kbouncer: Efficient and transparent rop mitigation[END_REF] uses the Detours framework [START_REF] Hunt | Detours: Binary interception of win 32 functions[END_REF] to rewrite a binary and make it stop each time a sensitive function call is performed. Once stopped, kBouncer takes over and checks the Last Branch Record (LBR) unit of an Intel x86 processor. The LBR unit records all the last branches performed by the processor. From the LBR, kBouncer filters the sources and destinations of the last "returns" performed by an application. kBouncer checks that each return destination is preceded by a call. If not, a code reuse attack is detected and blocked. While the estimated runtime overhead of kBouncer is up to 6%, kBouncer suffers from many limitations. Indeed, kBouncer relies on the Last Branch Record (LBR) records; unfortunately, the latter may be overflowed or polluted by the context switches of the Windows operating system. Moreover, kBouncer is only designed to detect Return-Oriented Programming attacks. However, attacks such as Jump-Oriented Programming [START_REF] Bletsch | Jump-Oriented Programming : A New Class of Code-Reuse Attack[END_REF] are as practical and dangerous than Return-Oriented attacks. At last, kBouncer only intercepts dangerous function calls. Unfortunately, many attacks are not always using a sensitive function call in their exploit. Consequently, a wide range of attacks may evade the kBouncer engine.

ROPGuard [START_REF] Fratrić | ROPGuard : Runtime Prevention of Return-Oriented Programming Attacks[END_REF] is an alternative to kBouncer [START_REF] Pappas | kbouncer: Efficient and transparent rop mitigation[END_REF] which operates in the same way.

As kBouncer, ROPGuard is triggered each time a sensitive function is called in a program. Then, ROPGuard performs more advanced verification than kBouncer to determine whether a program is currently being exploited. First, ROPGuard checks that the stack pointer still belongs to the stack area. Many advanced exploits use the stack pivot technique to move the stack pointer is the heap or the BSS where a gadget sequence can be placed by an attacker. Second, ROPGuard checks if the return address of the called sensitive function belongs to an executable memory area and is preceded by a call instruction. Indeed, many Return-Oriented Programming attacks jump all over the program breaking the classical "call" and "return" structure. Third, ROPGuard tries to compute the call stack of the sensitive function based on the previous frame pointers stored in the stack. Return-oriented gadgets are injected in the memory space overwriting several stack frames and previous frame pointers. Finally, ROPGuard provides additional features such as preventing a program to make the stack executable and simulating a critical function to observe its return address. Unfortunately, by only hooking sensitive function calls, ROPGuard suffers from the same limitation as kBouncer.

To overcome the limitation of both kBouncer [START_REF] Pappas | kbouncer: Efficient and transparent rop mitigation[END_REF] and ROPGuard [START_REF] Salwan | ROPgadget[END_REF], ROPecker [START_REF] Cheng | ROPecker : A Generic and Practical Approach For Defending Against ROP Attack[END_REF] enforces three signatures detection methods such as the number of instructions between branches, the number of branches over a time window and, the use of sensitive functions.

ROPecker is purely implemented in software in the Linux kernel and operates in two Chapter 1. Background steps. First, before being executed, the monitored program is pre-processed by ROPecker.

This processing phase constructs a gadget database of the application. Then, at runtime ROPecker restricts the execution of functions to their authorized pages by setting the other pages as non-executable. As a result, when a program tries to execute an instruction outside of the active page an exception is captured by the ROPecker engine. This exception triggers the heuristic algorithm of ROPecker. The latter leverages the Last Branch Record (LBR) history to check whether the last source/destination branches correspond to gadget addresses already stored in the gadget database. Besides, ROPecker analyzes the top of the stack and looks for gadget addresses to anticipate future attacks. Thanks to the gadget database ROPecker can detect jump-oriented programming attacks [START_REF] Abbasi | Challenges in designing exploit mitigations for deeply embedded systems[END_REF] where both kBouncer and ROPGuard fail.

Unfortunately, heuristic countermeasures are imperfect. Heuristic engines are weak at detecting call-preceded gadgets [START_REF] Carlini | ROP is Still Dangerous : Breaking Modern Defenses[END_REF]. Also, heuristic engines may be defeated by introducing long gadgets that include several instructions and function calls. The main purpose of these long gadgets is to evade the heuristic engine by obfuscating the signature of a classical Return-Oriented Programming exploit.

To counteract evasion methods, SCRAP [START_REF] Kayaalp | SCRAP : Architecture for Signature-Based Protection from Code Reuse Attacks[END_REF] proposes a heuristic analysis coupled with a hardware shadow stack. SCRAP is based on a modified implementation of an x86

processor. As ROPecker [START_REF] Cheng | ROPecker : A Generic and Practical Approach For Defending Against ROP Attack[END_REF], SCRAP [START_REF] Kayaalp | SCRAP : Architecture for Signature-Based Protection from Code Reuse Attacks[END_REF] noticed that many heuristic analyses [START_REF] Pappas | kbouncer: Efficient and transparent rop mitigation[END_REF][START_REF] Cheng | ROPecker : A Generic and Practical Approach For Defending Against ROP Attack[END_REF] only focus on return-oriented programming attacks, but not on jump-oriented programming attacks. Moreover, SCRAP takes into account that the heuristic engine can be evaded using long intermediate gadgets that include calls. To overcome these two issues, SCRAP uses a counter to measure the length of gadgets in real-time. If a gadget length may happen to be under a threshold, a transition is performed in a finite-state machine.

Conversely, if a gadget length is over a threshold, a step back is performed by the finite state machine. When a function call is performed, the current state of the finite-state machine is saved in a shadow stack and the finite-state machine is re-initialized. When the function returns, the state is restored and SCRAP continues to monitor gadgets. In terms of security, SCRAP [START_REF] Kayaalp | SCRAP : Architecture for Signature-Based Protection from Code Reuse Attacks[END_REF] can detect any code-reuse attack, even the evasion techniques that introduce long intermediate gadgets. Also, the detector engine of SCRAP can be programmed to monitor up to 50 instruction gadget lengths without any false positive.

Finally, SCRAP is implemented through the PLTsim simulator and reports an execution overhead of less than 2%.

Heuristic defenses takeaways

• Heuristic defenses act like anti-virus, they detect control-flow attacks signature.

• Heuristic defenses are completely transparent to binaries, they often do not require any code instrumentation.

• Heuristic protections are vulnerable to attacks that evade known controlflow signatures.

Software diversity

When a vulnerability is discovered, an attacker aims to develop an exploit and compromise as many systems as possible. The reason why large-scale exploits are usually functional comes from the fact that each instance of an application is the same at the assembly level.

Thus, each instance of a program has the same set of gadgets and therefore is vulnerable to the same exploit. To reduce the effectiveness of large-scale exploits, one idea is to diversify the instances of a program in memory.

As previously studied in section 1.2.1.1, the Address Space Layout Randomization (ASLR) is a technique to diversify programs' heap/stack. To remind, the partial ASLR inserts the position of the stack/heap at a random offset each time an application is executed. In contrast, the complete ASLR places the whole application, including the "text" section at a random offset in memory. The original goal of the partial ASLR is to mitigate code injection attacks. In the same way, the full ASLR mitigates the so-called return-oriented programming attacks by shifting the position of the "text" section at each execution.

Unfortunately, the current implementations of the ASLR are weak. Indeed, partial ASLR can be evaded using Return-Oriented Programming attacks. Moreover, codememory disclosures caused by dangling pointers may reveal the position of code memory pages allowing an attacker to retrieve gadgets on-the-fly [START_REF] Shacham | On the Effectiveness of Address-Space Randomization[END_REF]. Finally, the ASLR is also vulnerable to partial overwrite attacks and brute-force attacks [START_REF] Bittau | Hacking Blind[END_REF][START_REF] Liu | Launching Return-Oriented Programming Attacks against Randomized Relocatable Executables[END_REF]] that aim at trying every possible offset to match an address with a fixed exploit. It turns out that the random offset protection used by the ASLR offers a coarse-grained software diversification.

According to the state-of-the-art of P. Larsen et al. [START_REF] Larsen | SoK : Automated Software Diversity[END_REF], fine-grained software diversification can be obtained by randomizing the code structures of an application. To achieve diversification, several hardware/software transformation techniques can be applied to generate several mutations of the same program instance. To enforce software diversity, Jackson et al. [START_REF] Jackson | Diversifying the Software Stack Using Randomized NOP Insertion[END_REF] proposed two extensions of the current GCC [START_REF] Griffith | GCC: The Complete Reference[END_REF] and LLVM [START_REF] Lattner | LLVM: A compilation framework for lifelong program analysis & transformation[END_REF] compilers. These extensions aim at inserting random NOP instructions between the instructions of a program. This has the effect of inserting random offsets between instructions, complicating the deployment of accurate code-reuse attacks.

Unfortunately, this model provides low entropy. The order of the functions and the basic blocks remains the same in memory and is frozen after compilation. It results that some implemented ILR [START_REF] Hiser | Ilr: Where'd my gadgets go?[END_REF] (Instruction Location Randomization) a framework that shuffles every instruction in a binary. To be executed in the right order, ILR maintains a fall through map where each instruction's successor is independent of its location. This map is used by a virtual machine to fetch the instructions in the right order and executes them. This approach enforces a high level of randomness; every instruction is located at a different address every time. Unfortunately, the fall through map more than double the 1.3. Existing Defenses size of the application which is unreasonable for memory-constrained embedded systems.

Binary Stirring is a technique introduced by R. Wartwell [START_REF] Wartell | Binary Stirring : Self-randomizing Instruction Addresses of Legacy x86 Binary Code[END_REF] that dispenses with a virtual machine to maintain software diversification. They randomize both the basic blocks and the instructions at load time. To perform such randomization, they developed a tool that disassembles binaries into an intermediate representation. This intermediate representation is then followed by a load time phase that randomizes and rewrites the instruction of the program. Compared to ILR, STIR is much lighter and does not require a virtual machine. Moreover, STIR has a fairly acceptable run-time overhead of 1.6%.

Unfortunately, countermeasures based on binary randomization suffer from the Just-In-Time Return-Oriented Programming (JIT-ROP) attack introduced by L. Davi [START_REF] Snow | Just-in-time code reuse: On the effectiveness of fine-grained address space layout randomization[END_REF]. Such an attack leverages a memory disclosure to leak the text section of a program, disassemble it, and build on-the-fly ROP exploits. L. Davi [42] demonstrated that JIT-ROP is powerful enough to break any sort of randomization defenses previously exposed.

To prevent JIT-ROP, one solution is to prevent memory leaks by enforcing an "executeonly" policy on certain memory areas of the program's "text" section [START_REF] Gionta | HideM : Protecting the Contents of Userspace Memory in the Face of Disclosure Vulnerabilities Categories and Subject Descriptors[END_REF]. Another method proposed by SOFIA [START_REF] Clercq | SOFIA : Software and Control Flow Integrity Architecture[END_REF] is to cipher every instruction of a program based on its control-flow graph. At run-time, every instruction is deciphered using both the current and the previous program counter. Thus, if the previous program counter does not respect the intended execution-flow, the instruction deciphering fails. As a result, SOFIA prevents both JIT-ROP and various software control-flow attacks. On top of that, SOFIA is also able to thwart hardware fault injection attacks that aim at skipping instructions.

Unfortunately, due to the encryption, SOFIA incurs a high run-time overhead up to 106% with a 23.3% penalty on the clock speed of the LEON3 processor.

Software diversity takeaways

• Software diversity produces multiple instances of the same software to prevent exploit development.

• Software diversity is highly vulnerable to memory disclosure attacks and JIT-ROP.

• The size and execution-time overhead induced by software diversity rely on the randomization technique and the entropy source.

Data-flow integrity

The previously discussed defenses protect against the second stage of memory-based attacks. To remind, the first stage of an attack is the corruption of either control or noncontrol-flow data. The second stage is the execution of a malicious payload by the corrupted program. Control-flow integrity, heuristic analysis, and software diversification take into account that an attacker already corrupted sensitive data. Their main purpose is to harden and/or detect the deployment of a functional exploit. This section takes a different approach, it focuses on defenses against the first stage of an attack, i.e. the initial corruption of sensitive data. However, what can be considered as programs' critical data?

Given the previous sections, control-flow data can be considered sensitive. This includes return address for indirect backward-edges and, function pointers for indirect forward-edges. Once corrupted, this data can be leveraged by attackers to hijack the execution flow. Besides, section 1.1.1 introduced data-oriented attacks, a practical class of attacks that modify the behavior of an application without relying on control-flow data.

These powerful attacks unlock security restrictions and give more control of a program to an attacker. To remind, H. Hu and al. [START_REF] Hu | Data-Oriented Programming : On the Expressiveness of Non-Control Data Attacks[END_REF] demonstrated the Turing-completeness of data-oriented attacks using vulnerable loop variables and arbitrary writes in memory. As a result, non-control data loops and data pointers may also be considered sensitive. Finally, back to the discussion on critical systems, it seems that any non-control data inducing a faulty behavior in a system can be considered sensitive.

Unlike control-flow integrity that restricts the execution flow to the control-flow graph, data-flow integrity aims at protecting programs at the sensitive data granularity. Data-flow integrity can be achieved using cryptography, fat-pointers, isolation, and tagged memory.

This section discusses each of these approaches mentioning their accuracy and costs.

Cryptographically enforced data-flow integrity

Cryptography is a discipline of cryptology that can be applied to ensure sensitive data-flow integrity. The cryptography certifies the confidentiality, authenticity, and integrity of a message. Thus to protect sensitive data, a cryptographic algorithm with a private key can be applied to attest to the integrity of sensitive data whenever accessed.

For instance, CCFI [START_REF] Mashtizadeh | Cryptographically Enforced Control Flow Integrity[END_REF] an LLVM compiler extension proposed by A.J. Mashtizadeh PointGuard TM [START_REF] Cowan | PointGuardTM: Protecting Pointers From Buffer Overflow Vulnerabilities[END_REF] is another compiler extension based on GCC that protects pointers. To do so, PointGuard TM generates a unique stream cipher key at program initialization. Then, each pointer stored in memory is ciphered using the key. At runtime whenever pointers are accessed they are ciphered/deciphered using the key. In comparison with CCFI [START_REF] Mashtizadeh | Cryptographically Enforced Control Flow Integrity[END_REF] that guarantees the pointers' integrity, PointGuard TM uses the confidentiality property of cryptography to protect sensitive data. As a result, if a ciphered pointer is maliciously modified, its decryption may result in an erroneous value causing the application to crash. PointGuard TM [START_REF] Cowan | PointGuardTM: Protecting Pointers From Buffer Overflow Vulnerabilities[END_REF] reports an overhead ranging from 0 to 20% depending on the application. Unfortunately, PointGuard TM suffers from two limitations. First, PointGuard TM uses an XOR stream cipher with a unique key to cipher multiple pointers.

As a result, it is vulnerable to many time pad attacks. Second, PointGuard TM does not enforce any specific security policy against memory disclosure. It follows that a memory disclosure may easily reveal the value of the key. Finally, as CCFI [START_REF] Mashtizadeh | Cryptographically Enforced Control Flow Integrity[END_REF], PointGuard TM [START_REF] Cowan | PointGuardTM: Protecting Pointers From Buffer Overflow Vulnerabilities[END_REF] does not enforce non-control data integrity leaving programs vulnerable to [START_REF] Hu | Data-Oriented Programming : On the Expressiveness of Non-Control Data Attacks[END_REF].

To overcome the limitation of PointGuard TM [START_REF] Cowan | PointGuardTM: Protecting Pointers From Buffer Overflow Vulnerabilities[END_REF], S. Bhatkar and R. Sekar proposed Data Space Randomization (DSR) [START_REF] Bhatkar | Data Space Randomization[END_REF]. DSR is a C front end code instrumentation framework based on CIL [START_REF] Mcpeak | CIL: Intermediate language and tools for C program analysis and transformation[END_REF]. Data space randomization ciphers every data in the memory using a mask. To avoid many time pad attacks, this mask is different for every ciphered data. As a result, DSR offers a higher level of security than PointGuard TM . Besides, the solution induces an execution-time overhead ranging from 15%-28%, which is close to PointGuard TM . Unfortunately, DSR is not binary compatible with external libraries and modules can't be compiled separately. DSR is, therefore, constraining for incremental compilation.

Finally, Pointer Authentication Code (PAC) [START_REF] Liljestrand | PAC it up : Towards Pointer Integrity using ARM Pointer Authentication[END_REF][START_REF]Pointer Authentication on ARMv8 . 3[END_REF] is a hardware extension of ARM 64 bits processors that use Message Authentication Code (MAC) to verify the integrity of pointers at runtime. The PAC hardware extension comes with an extended compiler and provides two sets of custom instructions (PAC* and AUT*) to authenticate pointers at program execution-time. The PAC* instructions trigger a hardware MAC accelerator that computes the MAC of a pointer using QARMA [START_REF] Avanzi | The QARMA Block Cipher Family. Almost MDS Matrices Over Rings With Zero Divisors, Nearly Symmetric Even-Mansour Constructions With Non-Involutory Central Rounds, and Search Heuristics for Low-Latency S-Boxes[END_REF] block cipher. The result of the MAC is stored in the 26 upper top-bits ignore of the pointer. This comes from the fact that the ARM64 Linux uses a 40-bit address space by default, leaving 26 upper bits unused.

Once the pointer is re-accessed, the AUT* instruction is used to verify the MAC and restore the pointer original value. If the pointer authentication fails, the processor makes the pointer value an illegal address. When it comes to code pointers and return addresses protection the execution-time overhead induced by PAC is very low (under 0,5% on average) [START_REF] Liljestrand | PAC it up : Towards Pointer Integrity using ARM Pointer Authentication[END_REF]. This low overhead is very encouraging; it demonstrates that finegrained control-flow integrity can be achieved without inducing unwanted execution-time Chapter 1. Background overhead. However, concerning the data pointers, [START_REF] Liljestrand | PAC it up : Towards Pointer Integrity using ARM Pointer Authentication[END_REF] claims that the run-time overhead largely depends on the memory profile of an application. The paper [START_REF] Liljestrand | PAC it up : Towards Pointer Integrity using ARM Pointer Authentication[END_REF], reported up to 39,5% overhead.

Cryptographically enforced data-flow integrity takeways

• Cryptographically enforced data-flow integrity uses cryptographic algorithms to authenticate/protect sensitive data integrity.

• By protecting sensitive data, cryptographically enforced data-flow integrity ensures fine-grained control-flow integrity.

• Implemented with hardware support, cryptographically enforced dataflow integrity has a very low execution-time overhead.

Fat Pointers

Every programs' variable has a memory location that can be retrieved thanks to its address.

Pointers are specific variables that dereference a memory location by its address. They are commonly used to efficiently dereference data structures such as strings, tables, trees, but also to call indirect subroutines (indirect forward-edges). In most memory-based attacks, attackers leverage in-memory pointers to modify the behavior of a program. By modifying the value of a pointer, an attacker can make it dereference another variable that is later reused by the program.

One way to prevent pointer hijacking is the use of Fat Pointers. Fat Pointers are extended pointers that include extra information such as their base and bounds. Figure 1.19 illustrates both a simple pointer and a fat pointer. One can observe that both pointers in Figure 1.19 dereference the same variable. However, the Fat Pointer has additional metadata: a base and a bound. These data refer to the beginning and the limit of the dereferenced object in memory. Hence, each time object A is dereferenced using the Fat Pointer, the validity of the latter is checked using the additional base and bound metadata.

The use of Fat Pointers is an efficient technique to thwart pointer hijacking attacks.

Intel MPX [START_REF] Oleksenko | Intel MPX Explained[END_REF], Watchdog [START_REF] Nagarakatte | Watchdog : Hardware for Safe and Secure Manual Memory Management and Full Memory Safety[END_REF], WatchdogLite [START_REF] Nagarakatte | WatchdogLite : Hardware-Accelerated Compiler-Based Pointer Checking[END_REF], Softbound [START_REF] Nagarakatte | SoftBound : Highly Compatible and Complete Spatial Memory Safety for C[END_REF], and Hardbound [START_REF] Devietti | HardBound : Architectural Support for Spatial Safety of the C Programming Language[END_REF] broadly follow the same Fat Pointer approach to ensure memory safety. For instance, both Softbound [START_REF] Nagarakatte | SoftBound : Highly Compatible and Complete Spatial Memory Safety for C[END_REF] and Hardbound [START_REF] Devietti | HardBound : Architectural Support for Spatial Safety of the C Programming Language[END_REF] record metadata for every in-memory pointers.

These metadata are stored in a disjoin memory in the virtual address space and they include the base and bound of every pointer. Whenever a pointer is used, the boundaries of the latter are checked using its associated metadata. Softbound [START_REF] Nagarakatte | SoftBound : Highly Compatible and Complete Spatial Memory Safety for C[END_REF] is a pure software approach that inserts bound checks at compile time. Softbound is compatible with the C language programming standards, however, the execution overhead cost of Softbound is very high, up to 79%. To overcome the overhead limitation of Softbound, Hardbound implements a hardware extension of an Intel x86 processor with a custom instruction to set the base and bound of a pointer in the disjoin memory. The hardware extension also implicitly monitors each access to a pointer and check its boundaries. As Softbound [START_REF] Nagarakatte | SoftBound : Highly Compatible and Complete Spatial Memory Safety for C[END_REF],

1.3. Existing Defenses Moreover, according to the evaluation performed by O. Oleksenko et al. [START_REF] Oleksenko | Intel MPX Explained[END_REF], MPX only protects against 46% of the attacks included in the RIPE benchmark suite [START_REF] Wilander | RIPE: runtime intrusion prevention evaluator[END_REF].

In the same purpose, Shakti-T [START_REF] Menon | Shakti-T : A RISC-V Processor with Light Weight Security Extensions[END_REF] is a RISC-V [START_REF] Waterman | The risc-v instruction set manual; volume ii: Privileged architecture, sifive inc. and cs division, eecs department[END_REF] processor architecture that enforces data-flow integrity following the Fat Pointer approach. Shakti-T extends the RISC-V architecture by introducing new instructions and specific memory support for Fat Pointers. At execution-time, Shakti-T maintains a Pointer Limit Memory (PLM) to store the base and bound of every pointer. The base address of the PLM is conserved in a ded-Chapter 1. Background icated Pointer Limits Base Register (PLBR), and every pointer is associated with an ID stored alongside in the regular memory. To speed up the access to the PLM, the Shakti-T architecture implements a Base and Bound Cache (BnBCache). This cache is composed of two elements, a Base and Bound Index (BnBIndex) and a Base and Bound Look Up (BnBLookUp) table. Each index of the BnBLookUp maintains the base, the bound, the ID, and a validity bit of a pointer in the PLM. Moreover, the BnBIndex is an extension of the register file that holds an index for each general-purpose register to an entry in the Base and Bound Cache.

The Fat Pointer hardware support proposed by Shakti-T is driven by specific customized instructions introduced in the RISC-V instruction set. For instance, a special write instruction [START_REF] Menon | Shakti-T : A RISC-V Processor with Light Weight Security Extensions[END_REF] (wrplm) is provided to populate the PLM memory with the base and bound value of a pointer. Also, special load instructions are provided to load the base and bound values from the PLM to the BnBCache, load a pointer with its ID into a general-purpose register and checks its validity using the BnBCache. In terms of security, no specific evaluation is performed by Shakti-T however, they claim to thwart both spatial and temporal attacks with around no performance overhead.

Fat Pointers takeaways

• Fat Pointers extend regular pointers with metadata such that they keep track of their base and bound.

• Fat Pointers require additional memory space to keep track of the limits of each pointer

• Fat Pointer ensures fine-grained control-flow integrity.

Sensitive data isolation

When executing a common C application in memory, it appears that security-critical and non-security critical data are interleaved. For instance, a function's stack holds the return address of the function (control-flow data), some buffers, pointers (code-pointers and data-pointers), some loop control data (non-control data) and also security-critical tokens (security-critical data). Unfortunately, due to this configuration, sensitive data that are spatially close to vulnerable buffers may be tampered by out-of-bound attacks.

One way to tackle this issue is to disjoin the memory space in two parts, one for the non-security critical data and the other for the security-critical data. Figure 1.20, displays this concept of sensitive data isolation.

In Figure 1.20, an additional memory area (safe memory space) is introduced in the memory layout of the application. This safe memory space is disjoined from the other data memory areas. Thus, by placing the security-critical data (pointers/return addresses) in the safe memory region and leaving non-sensitive data in the stack, it is conceptually harder and even impossible for a spatial vulnerability to reach this disjointed area.

Existing Defenses

.20: Sensitive data memory separation

To avoid any confusion, it is important to point out that the principle of sensitive data isolation in the example is different from Software Fault Isolation (SFI) [START_REF] Wahbe | Efficient Software-Based Fault Isolation[END_REF]. SFI technology such as TrustZone [START_REF] Arm | Security technology building a secure system using trustzone technology[END_REF] maintains different memory areas where sensitive parts of an application can be isolated. The main purpose of SFI is to segregate sensitive parts of application code or isolate some tasks in a multi-tasks application such that vulnerability does not spread through the entire system. While SFI restricts the attack surface of a memory exploit, it does not ensure sensitive data-flow integrity.

Code pointer separation (CPS) [START_REF] Kuznetsov | Code-Pointer Integrity[END_REF] introduced by V. Kuznetsov et al., follows the concept of memory space isolation. CPS creates two data memory space, one for sensitive code pointers and the other one for the non-sensitive pointers. To achieve sensitive code-pointers isolation, CPS maintains a disjoined safe stack memory area and a disjoined safe heap memory area. Every sensitive code pointer such as function pointers and return address pointers are always placed in the safe area while the other data/pointers remain in the regular stack. The isolation between the sensitive code pointers and the insensitive is guaranteed at the instruction level by the compiler. Indeed, V. Kuznetsov et al. [START_REF] Kuznetsov | Code-Pointer Integrity[END_REF] implemented a plugin in the LLVM compiler that identifies sensitive code pointers and generates the correct instruction flow to store them in the safe area. According to [START_REF] Nagarakatte | Watchdog : Hardware for Safe and Secure Manual Memory Management and Full Memory Safety[END_REF],

CPS induces a very low execution-time overhead ranging from 8.4% to 10.5%. Unfortunately, CPS only protects code pointers with one level of dereferencement. Consequently, every pointer indirectly calling an indirect function pointer is not considered sensitive by CPS and then not protected by the safe stack. It follows that a memory-based attack can leverage such pointers to execute malicious code. To overcome this limitation V. [START_REF] Kuznetsov | Code-Pointer Integrity[END_REF] (CPI) an improved implementation of CPS. CPI aims at placing every sensitive code pointer in the safe area as well as every pointer that may dereference a sensitive code pointer. Both CPI and CPS thwart every at-Chapter 1. Background tack from the RIPE [START_REF] Wilander | RIPE: runtime intrusion prevention evaluator[END_REF] benchmark suite. This is very encouraging since CPI induces less than 11% execution-time overhead. Unlike control-flow integrity, CPI does not perform any sanity checks on code pointers, it just prevents their corruption thanks to isolation.

Kuznetsov et al. proposed code pointer isolation

Unfortunately, as clearly mentioned in their implementation [START_REF] Kuznetsov | Code-Pointer Integrity[END_REF], CPS and CPI do not mitigate the so-called data-flow oriented programming attack [START_REF] Hu | Data-Oriented Programming : On the Expressiveness of Non-Control Data Attacks[END_REF]. Indeed, CPI and CPS only protect code pointers and not data pointers. In a recent attack, I. Evans [START_REF] Evans | Missing the Point(er): On the Effectiveness of Code Pointer Integrity[END_REF] leverage data pointers that are not protected by CPI/CPS to leak the position of the safe memory and perform an arbitrary write on the code-pointers inside.

Data-isolation takeaways

• Sensitive data isolation maintains two different memory space, one for sensitive data and one for regular data. Data isolation is usually achieved with instruction level separation.

• Software-based data-flow isolation induce an acceptable execution-time overhead.

Tagged sensitive data

The previous section exposed the mechanisms used to isolate sensitive data. In the example of CPI and CPS [START_REF] Kuznetsov | Code-Pointer Integrity[END_REF], sensitive data isolation is achieved at the instruction level. The LLVM [START_REF] Lattner | LLVM: A compilation framework for lifelong program analysis & transformation[END_REF] compiler plugin of CPI and CPS ensures that any load and store instruction manipulates sensitive data using the safe memory. The principle of tagged memory broadly reuses the same instruction separation approach introduced by CPI.

First, tagged memories provide additional tag information to data objects. At compilation time, every read and write instruction is associated with the tags' object it modifies.

At execution-time, the instrumented write instructions mark each written memory location with its associated tag. When an object is accessed using a read instruction, the tag of the object is compared with the tag of the instruction to verify that the object has not been overwritten by a different tag instruction. In a second step, the compiler instrument every read and write instruction to track the data-flow at execution-time. In the third step, at execution-time, the program maintains a Reaching Definition Table (RDT). The RDT records the last instruction that defined a memory location. Then, when this memory location is used by a read instruction; the program consults the RDT to check whether the last instruction that defined the current value is compliant with the precomputed data-flow graph. As a result, DFI is efficient at tracing and detecting data-oriented attacks. Unfortunately, applied to embedded systems it raises challenges. Indeed, DFI induces an execution-time overhead ranging from 43%

to 104% [START_REF] Castro | Securing software by enforcing data-flow integrity[END_REF]. Also, the size of the reaching definition table is around 50% of the instrumented application which may be prohibitive for memory-constrained embedded systems.

Write Integrity Testing (WIT) [START_REF] Akritidis | Preventing memory error exploits with WIT[END_REF] also introduced by Microsoft Research follows the principle introduced by DFI. At compile-time, WIT uses an inter-procedural analysis to compute the set of memory objects that are defined by write instructions. Then, WIT assigns a color to each memory object and the instruction that can define them. During execution-time, WIT ensures that each write instruction defines a memory object that has the same color. The program also maintains a color table that is updated when objects are allocated and de-allocated. Unlike DFI [START_REF] Castro | Securing software by enforcing data-flow integrity[END_REF] that checks the last instruction that defined sensitive data, WIT prevents memory exploits from defining sensitive data. Besides, WIT only instruments the unsafe write instructions. Thus, the color table maintained but WIT is smaller than the RDT of DFI with an extra size overhead of 12,5%. The average execution-time overhead induced by WIT is around 10% with a maximum of 25% on the SPEC CPU2000 [START_REF] Henning | SPEC CPU2000: Measuring cpu performance in the new millennium[END_REF]. In terms of security, both DFI and WIT are challenged with realworld data-flow and control-flow attacks on the NullHttpd HTTP server. It seems that they both detect any real exploits.

Hardware-Assisted Data Flow Isolation (HDFI) [START_REF] Song | HDFI : Hardware-Assisted Data-flow Isolation[END_REF] and LowRISC [START_REF] Song | Towards general purpose tagged memory[END_REF] tagged mem-Chapter 1. Background ory are hardware approaches to Data Flow Integrity (DFI) introduced by Microsoft Research. For instance, HDFI uses two tag levels (IL1 and IL0) to separate sensitive data (IL1) from regular data (IL0). To trace the data-flow, HDFI extends the open-source RISC-V processor memory with an additional one-bit tag field for every word. Furthermore, to enforce sensitive data isolation, HDFI introduces a custom store and a custom load instruction in the RISC-V Instruction Set Assembly (ISA). To support these instructions, the processor logic is modified such that; every regular write instruction defines a data and set the tag field to zero, every special write instruction defines a sensitive data and set the tag field bit to one and every special load instruction checks that the used sensitive data has a tag set to one. Thus, a regular write that modifies sensitive data also changes its tag. When this sensitive data is re-used by a custom load instruction, the processor detects a wrong tag and raises an exception. Following the HDFI concept, it appears that each data requires two memory accesses, one for the tag and one for the value. Therefore, to not undermine the memory access performance, HDFI maintains an additional L1 and L2 cache for the tag. Finally, HDFI comes with both an extended GCC and LLVM compilers which ensure the instruction level isolation between sensitive data and regular data. In terms of security, HDFI detects any attack from the RIPE benchmark suite with an average overhead of 2% on the SPEC CPU CINT 2000 [START_REF] Song | HDFI : Hardware-Assisted Data-flow Isolation[END_REF].

Tagged sensitive data takeaways

• Tagged memory are used to track every write instruction in a program and check if it corresponds to a static data-flow graph.

• Pure software data-flow integrity is expensive in both execution-time and memory size.

• Hardware assisted tagged memory are highly effective in security, inducing a very low execution-time overhead.

1.4. State of the Art Synthesis

State of the Art Synthesis

This section summarizes the defenses previously discussed. It discusses the strengths and weaknesses of control-flow integrity, heuristic countermeasures, software diversity, and data-flow integrity. The main goal of this synthesis is to prepare the following Chapter in which the thesis highlights why critical medical devices face security issues and why the approaches proposed in the related state-of-the-art are not the most appropriated for them. In a nutshell, this synthesis contributes to exposing the gap between the existing security defenses and the security required by the life-critical systems.

Control-flow integrity discussion

Regarding control-flow integrity, Table 1.1 displays a summary of various control-flow integrity concepts approached in the state-of-the-art. These concepts are summarized regarding the protection they offer such as backward-edge (BW), and forward-edge (FW). Regarding the security, control-flow integrity is globally efficient at mitigating both code injection and code-reuse attacks. Unfortunately, each approach suffers from minor limitations that still leave opportunities for an attacker to execute a successful attack.

For instance, coarse-grained policies cannot guarantee that indirect branches target valid destination sites with 100% accuracy. As a result, attackers can still perform attacks that comply with enforced coarse-grained control-flow protection [START_REF] Carlini | ROP is Still Dangerous : Breaking Modern Defenses[END_REF]. Some of these attacks are practical, they leverage call-preceded gadgets that do not break the control-flow policy to execute malicious code.

Regarding the costs, it seems that pure software-based control-flow integrity protections induces higher execution-time overhead than hardware-software codesign. For instance, [START_REF] Abadi | Control-Flow Integrity Principles, Implementations, Applications[END_REF], and [START_REF] Abera | C-FLAT: Control-FLow ATtestation for Embedded Systems Software[END_REF] induce a non-negligible execution-time overhead (21% and up to 72% respectively, see Table 1.1). Besides, purely software protections drastically increase the size of applications [START_REF] Zhang | Control flow integrity for cots binaries[END_REF], which could be prohibitive.

According to Table 1.1, control-flow integrity is deterministic, these solutions rely on labels, shadow call stacks, trampolines, and branch restrictions that do not introduce randomness in protected systems. In terms of modularity, not all existing concepts in Table 1.1 are compatible with incremental compilation and external non-protected libraries. For instance, most control-flow integrity prototypes based on labels rely upon post-compilation binary instrumentation. A lack of modularity is often difficult to integrate within the regular software engineering processes.

In closing, hardware-software codesigns present the best tradeoff between security and performances. For instance, labels or branch-restriction policies coupled with hardware shadow call stacks induce both a very low execution-time and size overhead. Unfortunately, although shadow call stacks provide fine-grained backward-edge control-flow integrity, their integration within real systems is challenging. First, they require dedicated handlers to manage goto issues such as the setjmp and "longjmp". Second, hardware shadow stacks are limited by the size of the buffer, a large call-depth may induce overflow managements. Finally, for multi-tasks systems, hardware shadow stacks should be assisted by operating systems and specifically schedulers to maintain stack coherency. Also, regarding security, software diversity becomes vulnerable when an in-memory vulnerability is coupled with a memory disclosure. In this case, an attacker leverages memory disclosure to de-randomize the application code. After de-randomization, the attacker disassembles the leaked memory and craft a Just-In-Time Return-Oriented Programming attack [START_REF] Snow | Just-in-time code reuse: On the effectiveness of fine-grained address space layout randomization[END_REF].

Heuristic defenses discussion

Software diversity discussion

Regarding the costs, software diversification induces extensive execution-time overhead depending on the implementation. According to Table 1.3 and section 1.3.2, the executiontime ranges from less than 1% overhead, up to more than the double of the original application. Finally, dynamic software diversification seems to be difficult to apply to low cost embedded systems. First, fine-grained randomization often requires the support of a powerful operating system or a virtual machine with an intermediate language [START_REF] Hiser | Ilr: Where'd my gadgets go?[END_REF] that rewrites the binary on-the-fly. Second, according to Table 1.3, software diversification can induce prohibitive size overhead. [START_REF] Bhatkar | Data Space Randomization[END_REF][START_REF] Castro | Securing software by enforcing data-flow integrity[END_REF]. While protecting code pointers enforces fine-grained control-flow integrity, data pointers protection and regular data protection highly complicate data-oriented attacks.

Data-flow integrity discussion

Unfortunately, directly from Table 1.4, it appears that the finer the security protection, the higher the execution-time overhead [START_REF] Castro | Securing software by enforcing data-flow integrity[END_REF]. This is, even more the case for pure software implementations. Indeed, data-flow integrity requires to trace and check every read and write operation performed by a program at run-time. While this ensures high granularity protection, the process is cumbersome inducing high execution-time and size overhead.

Like control-flow integrity, hardware support for data-flow integrity drops the executiontime overhead and the costs of the security.

As control-flow integrity, data-flow integrity does not rely on randomness. Every dataflow integrity protection reviewed in Table 1.4 can be considered deterministic. However, existing data-flow integrity protection is not always very modular, sometimes they require programs to be analyzed and instrumented as a whole to track each read and write operation [START_REF] Castro | Securing software by enforcing data-flow integrity[END_REF]. As previously mentioned this is convenient with incremental compilation approaches. Another drawback of most data-flow protection such as [START_REF] Mashtizadeh | Cryptographically Enforced Control Flow Integrity[END_REF][START_REF] Akritidis | Preventing memory error exploits with WIT[END_REF] is the compatibility with non-instrumented code. Indeed, instrumented code badly interfaces with non-instrumented code, preventing any continuity in the tracing of the data-flow.

State-of-the-art discussion

In closing, this Chapter highlights a state-of-the-art of memory-safety defenses. In the presented state-of-the-art, the existing works are grouped according to four main categories such as; control-flow integrity, heuristics, software diversity, and data-flow integrity. All Chapter 1. Background these protections raises the bar for attackers. It should be mentioned that the four presented categories include many more contributions than those presented in this manuscript.

Researchers try to solve the memory safety issue for more three decades by proposing the most innovative solutions. For instance, other areas of memory safety based safe-dialects such as Cyclone [START_REF] Grossman | Cyclone: A type-safe dialect of C[END_REF], and CCured [START_REF] Necula | CCured: Typesafe retrofitting of legacy software[END_REF] are not covered in this thesis's state-of-the-art.

Also, the field of control-flow integrity and data-flow integrity is not restricted to software security. It also covers many areas such as hardware security with other threat models.

While this thesis gives a global overview of the current existing security concepts, research progresses. Over the past few years, it has become apparent that increasingly more defense leverage open-hardware architectures [START_REF] Waterman | The risc-v instruction set manual; volume ii: Privileged architecture, sifive inc. and cs division, eecs department[END_REF]. According to the Tables 1.1, 1.2, 1.3, and 1.4, it is through a close combination of hardware and software that the most robust and optimal protection are achieved. These results provide directions for the approach of this thesis concerning the design of efficient memory safety defenses.

Regarding security, this state-of-the-art synthesis highlights that data-flow integrity may be the most accurate defense. Indeed, data-flow integrity is accurate enough to prevent multiple attacks such as code-reuse attacks and data-oriented attacks protecting sensitive data at various granularities. However, this synthesis also revealed that finegrained protection comes at a certain price such as time and size overhead. In front of that, critical systems have high-performance expectations, and to-date lack memory safety protections. To determine the finest defense for life-critical systems, the next Chapter study the root cause of memory safety issues in the context of medical devices, their security requirements, why the state-of-the-art can be improved, and the thesis's approach.

Approach

Summary of the Chapter

This Chapter follows the state-of-the-art. Although the previously exposed memory-safety defenses are effective, it seems that none of them are really integrated into life-critical medical devices due to several conceptual and constraint issues. As a first step, this Chapter exposes the gap and states the thesis problematic. From the problem exposure, this Chapter raises several criteria that should be taken into account when designing practical defenses for lifecritical medical devices. Finally, following such specifications, this Chapter exposes the thesis approach to improve software security embedded systems.

Problem statement

Problem statement

According to the state-of-the-art, various defenses against memory-based exploits are available and efficient. Some of these defenses have been increasingly deployed in desktops and operating systems in recent years. Even if they are imperfect, they still increase system security. Unfortunately, it would appear that medical devices do not take advantage of existing defenses and remain vulnerable to simple attacks. For instance, [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF] found multiple code injection attacks allowing remote code execution on commercial infusion pumps. These code injection attacks revealed that the system didn't possess even the most basic memory safety mitigations highlighted in the state-of-the-art. Also, the study conducted by [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF] reveals that these pumps were not designed following a threat model and secure coding practices. So there is an inconsistency. On the one hand, security is an important concern for critical medical devices. These devices are in direct interaction with the human body and may cause irreversible health damages in case of security breaches.

Knowing that the state-of-the-art of existing defenses provides various solutions, manufacturers should have implemented at least one of them in critical devices. Sadly, security studies of current systems reveal that critical medical devices are vulnerable to attacks that have been treated over 10 years in the past. Being aware of this inconsistency, this section investigates the security issue faced by medical devices and dissects it in several points, starting from explaining why wireless devices are still insecure and why existing defenses are not yet implemented.

Why critical medical devices are insecure?

The Internet of Things (IoT) is a competitive and fast-moving market. Manufacturers are rushing their products to get market leadership. Besides, there is no specific security standard for medical devices [START_REF] Bernsmed | Safety critical software and securityhow low can you go?[END_REF]. This lack of regulation encourages manufacturers to prioritize the functionalities of their products instead of spending time on security aspects.

Security tests and advanced vulnerability research are also time-consuming, inconsistent with the dynamic of the IoT market. Unfortunately, many critical devices are written in unsafe languages such as C. The design of these devices involves complex problems from hardware to software such as complexity, third-party services (sometimes outdated), realtime constraints, number of lines of code, wireless connectivity. Once again, covering all these aspects with security tests is time-consuming and difficult. As a result, it appears that the integration of security is poorly compatible with time-to-market and lack of regulation.

Many existing medical devices on the market are to date very safe and approved by the FDA [4]. This emphasizes that medical device manufacturers are experts in safety and able to release high-quality products. Unfortunately, safety focuses on unintentional actions that may be achieved by a device and overlooks the risk of intentional securityrelated malicious actions. Most of the cybersecurity issues like remote code execution happen when a critical device is connected to the network. Connecting a medical device to the network is a relatively recent trend and cannot be blamed knowing the IoT market.

Chapter 2. Approach Unfortunately, wireless features expose critical devices to new attacks that manufacturers were not confronted with in the past. Are manufacturers disarmed when integrating security in medical devices? In any case, both [START_REF]Hospira Multiple Products Buffer Overflow Vulnerability[END_REF] and [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF] reveal a lack of strong defenses in medical devices. Probably, connectivity requires advanced security experts to be properly integrated. Maybe companies lack security engineers [START_REF] Ventures | Cybersecurity jobs report[END_REF] and thus, security issues are left to non-security experts. One thing is certain, integrating security into a critical system cannot be improvised, leaving non-expert achieving such task often results in useless defenses that can't fend off an advanced attacker. The lack of security in medical devices can be explained by a lack of security expertise and especially by an increased attack surface due to connectivity.

Openness to research is also a means of improving systems' security. For instance, increasing big tech companies such as Intel, Google, and Microsoft offer bug bounty programs [START_REF] Kuehn | Analyzing bug bounty programs: An institutional perspective on the economics of software vulnerabilities[END_REF] allowing researchers to look for vulnerabilities in their products within a legal framework. Thus researchers may attack real systems and contribute to improving their security while being rewarded. Currently, there is no medical devices manufacturer that offer bug bounty platforms. Thus, many medical devices come with commercial constraints that prevent researchers to freely attack them and disclose vulnerabilities.

Open-source systems also contribute to the improvement of closed-source systems. Take

Why current defenses are not implemented in medical devices?

Interestingly, regarding memory exploits, the state-of-art proposes efficient protections. However, when looking at the real attacks on medical devices, none of these protections seems to be deployed [15,[START_REF]Hospira Multiple Products Buffer Overflow Vulnerability[END_REF][START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF]37,[START_REF] Radcliffe | Hacking medical devices for fun and insulin: Breaking the human scada system[END_REF]. One can easily note that there is a gap, why no protections are integrated into these systems? By reviewing state-of-the-art defenses, several points reveal that the existing defenses are not suitable for medical devices. First, many concepts offer an incomplete defense.

For instance, most of the control-flow integrity solutions provide either backward-edge or forward-edge protection. So an attacker can always attack forward-edges when backwardedges are protected and vice versa. As medical devices may be life-critical, they require robust and complete protection. Second, most of the fine-grained approaches induce a 2.1. Problem statement relatively high execution-time overhead. As a result, to reduce the execution-time cost, most fine-grained defenses are relaxed in coarse-grained defenses, leaving many more opportunities for attack. The major issue with memory safety is the trade-off between the execution-time cost and the accuracy of the protection. Unfortunately, wireless connected medical devices require both performance and accuracy. At the same time, these devices should meet very strict real-time constraints with the highest security protection. To remind, manufacturers use C because of its efficiency. Thus, they won't break this asset for incomplete security.

Most control-flow integrity approaches require application code to be instrumented afterward. This is not very modular and even impractical in the sense that developers can only perform security tests at the end of a system's development phase. While many implementations in the state-of-the-art provide the necessary toolchains to perform code instrumentation, control-flow integrity often breaks the modularity asset provided by the C language. Also, backward-edges control-flow integrity provided by shadow stacks faces compatibility with the C standards (see "setjmp/longjmp").

Heuristic methods seem to be a good compromise for critical systems in comparison with control-flow integrity. Especially hardware-assisted heuristic protections, they induce a low execution-time overhead and do not require application code to be instrumented.

Thus heuristic methods maintain the modularity and efficiency of the C programming language. Unfortunately, heuristic methods are incomplete security protection, they aim at detecting specific memory-based attack signatures such as code-reuse attacks. However, as exposed in the state-of-the-art, attackers use hybrid exploits to take over a system. As a result, attackers leverage the fact that heuristic defenses do not enforce a specific control-flow/data-flow integrity protection to evade the heuristic engine. Another issue with heuristic protections is time-to-check and false positives. Most heuristic engines have a certain detection delay between the moment an attack is performed and the moment it is detected. This is an issue for critical systems, an attacker may have changed critical data hard to restore afterward. Finally, the weakness of heuristic methods is the lack of accuracy and therefore the lack of robustness against advanced attacks.

The criticality of wireless medical devices prevents the implementation of certain types of defense. For instance, software diversity re-randomizes applications code at each execution by altering its instructions and structure (order of functions, basic blocks, and instructions). This practice makes the code non-deterministic and thus prevents an attacker from forging functional exploits in case of vulnerability. Unfortunately, non-deterministic code is strongly discouraged in safety-critical coding standards [START_REF] Rierson | A Practical Guide for Aviation Software and DO-178C Compliance[END_REF][START_REF] Bagnara | The misra c coding standard and its role in the development and analysis of safety-and security-critical embedded software[END_REF]. Safety-critical software manufacturers use C for determinism that is broken by software diversity. Another problem with software diversity is the resources needed to implement it. In the state-of-the-art, most software diversity solutions involve a powerful virtual machine or a modified operating system. These supports require huge memory space and consume a significant amount of power. Unfortunately, critical medical devices are tiny and should consume as little as possible. Often the embedded operating systems are real-time and lightweight. They cannot implement virtual machines. Moreover, the execution-time Chapter 2. Approach overhead of some software diversity protections is very high, up to 100%. This breaks the efficiency property of the C programming language. As a result, although software diversity complicates the development of successful exploits, it does not satisfy most of the safety coding guidelines required by critical medical devices. Therefore, software diversity methods are not the most appropriate defense for medical critical-devices.

Data-flow integrity differs from the other approaches because it mitigates the memorysafety issue at the root cause: the initial critical-data corruption. This approach prevents an attacker from modifying sensitive data thanks to the data-flow graph. In comparison with control-flow integrity, data-flow integrity is finer because it does not rely on control-flow graphs. Data-flow integrity could protect either control-data and non-control data. Unfortunately, according to the state-of-the-art, pure software implementations of data-flow integrity induce a very high execution-time overhead (see Chapter 1, section 1.4). Also, some implementation of data-flow integrity such as DFI [START_REF] Castro | Securing software by enforcing data-flow integrity[END_REF] are incompatible with third-party libraries, that again break the compatibility asset of C. Regarding hardware-software defenses, PAC [START_REF]Pointer Authentication on ARMv8 . 3[END_REF] can achieve fine-grained control-flow integrity through control-data integrity with less than 2% execution-time overhead. However, for critical non-control data, the execution-time overhead rises to 40%. That always brings up the tradeoff between accurate security and acceptable performance overhead.

In terms of practicality, the identification of sensitive non-control data is hard to perform automatically, most of the compiler and instrumentation toolchains provide codepointer protection and leave the implementation of sensitive code-data protection to the user. Knowing the lack of security expertise in the industry [START_REF] Ventures | Cybersecurity jobs report[END_REF], it is impractical to let developers instrument their code to protect sensitive non-control data. Thus the lack of proper software support does not ease the implementation of security in critical devices. For the moment, it seems that software data-flow integrity is not implemented in medical devices [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF]. Software data-flow integrity induces too much high executiontime overhead breaking the efficiency asset of the C programming language. Concerning hardware-software approaches, there is no dedicated implementation for critical embedded systems. Most implementations such as PAC [START_REF]Pointer Authentication on ARMv8 . 3[END_REF] are designed for personal desktop or mobile phone computers. This availability issue is also a reason why data-flow integrity is not currently used. Finally, even if data-flow integrity protections are promising in terms of security, it needs more research to better understand the assets of the C programming language.

Following this discussion, one can understand why critical medical systems do not integrate memory safety defenses. Most existing concepts exposed in the state-of-the-art are primarily intended for personal desktops and clouds than critical embedded systems.

To support this argument, it's enough to recognize a few concepts are challenged on a real life-critical system. Unfortunately, life-critical systems behave differently from personal computers. A security countermeasure can stop a traditional cloud application from executing malicious actions. Conversely, on critical systems, safety depends on security, and security issues are impacting safety. For a life-critical system, detecting security attacks is the first step, the second is defining how the system should react and recover without 2.1. Problem statement harming the user.

Most existing memory-based protection degrades the assets of the C programming language. Many protections degrade the portability, the modularity, the efficiency, the toolchain support, the determinism, and the standard of the C programming language in favor of security. Security researchers often forget that performance and portability are the main barriers [START_REF] Szekeres | Sok: Eternal war in memory[END_REF] for a countermeasure to be accepted. On top of that, many papers claim that they solved the memory safety issue until a new attack appeared [START_REF] Szekeres | Sok: Eternal war in memory[END_REF]. As a result, memory safety protections are hardly accepted by manufacturers. Besides, critical medical devices are not only facing memory-safety issues.

Cryptography, authentication, privacy, integrity, defense-in-depth, and safety should be considered and implemented along memory-safety. Hence, to be accepted along with other security countermeasures, memory protections must have as few constraints as possible.

Chapter 2. Approach

Important memory safety criteria for medical devices

From the problem statement (section 2.1), this section highlights several criteria that security countermeasures should take into account to run in consistency with critical devices. This thesis considers that proper memory safety protection for critical systems should adhere to the following criteria:

• Robustness: A memory exploit can take full control of a program by diverting its control-flow. Regarding critical devices, such attacks endanger the life of its users and may even kill. Such a disastrous scenario is unacceptable. The critical device security should be at the highest level. Unfortunately, memory exploits are powerful.

They leverage both control and non-control data at the lowest granularity to make an application execute malicious action. To restrict an attacker's capabilities at the lowest, critical-devices must enforce at least fine-grained protections. A vigorous defense is not inviolable, but the higher the granularity of the protection, the more an attacker's abilities are decreased.

• Performance: The performance penalty of a countermeasure is one of the first criteria to be considered before adopting a defense. Most countermeasures in the state-ofthe-art undermine performances. The performance penalty is generally measured by the execution speed decrease of an application. As manufacturers want to optimize their products at their best, a high execution-time overhead may be prohibitive for real-time constrained medical systems. Even if 10% overhead seems acceptable, manufacturers may not pay more 5% overhead for a security solution [START_REF] Szekeres | Sok: Eternal war in memory[END_REF].

• Space overhead: To be integrated into embedded systems, memory safety countermeasures should not induce unwanted memory overhead. Medical systems, especially in-body critical devices, are restricted in size. Manufacturers tend to reduce the space taken by an application to its lowest. As a result, protection carrying a large amount of metadata that increases the size of a binary over 100% is impractical.

Currently, there is no official number determining the memory overhead threshold accepted by manufacturers. Finally, memory safety countermeasures are going to be implemented along with other hardware-software protections. It further emphasizes that low size overhead is very important to leave space for other protections.

• Modularity: This criterion applies to software countermeasures based on both compilation or binary rewriting. As the C programming language allows developers to break complex programs into several sub-modules, their hardening must be achieved independently. Non-modular countermeasures are impractical in large scale projects were several developer teams are working on different parts of a system. Only modular countermeasures can be integrated into a practical software development lifecycle.

• Compatibility: Most countermeasures in the state-of-the-art are not compatible with all the C standards. For instance, the shadow stacks have issues with the classical 2.2. Important memory safety criteria for medical devices "setjmp/longjmp" functions. Even the use of "setjmp/longjmp" is prohibited in critical systems, many countermeasures are still not compatible with external noninstrumented libraries. While these libraries can be vulnerable to memory corruption, they allow incremental deployment. Finally, complex binary instrumentation protections are sometimes incompatible with verification and static analysis tools.

The use of the latter is common for critical systems to validate safety.

• Determinism: Critical embedded systems must be deterministic. Safety-critical standards prohibit any code practices that lead to non-deterministic behavior [START_REF] Rierson | A Practical Guide for Aviation Software and DO-178C Compliance[END_REF].

As a result, a safety-critical compatible countermeasure cannot use software diversity or polymorphic code. Finally, deterministic protection can be formally verified.

Unlike probabilistic protections, deterministic countermeasures can thwart certain types of attacks with over 100% success.

• Practicality: The ease of integration of a security countermeasure is important. As mentioned in the previous section, manufacturers do not always have detailed expertise in security. Thus, to be properly integrated, a security countermeasure must require minimum human interaction. Any security solution requiring a developer to manually instrument code is impractical and error-prone. Therefore, an ideal memory safety protection for critical systems must be easy to use and transparent to the user.

• Safety: Once life-critical systems have been developed by manufacturers, they are certified with safety standards. From the moment a system is certified it is assumed to be safe to use and immutable. Unfortunately, this assumption is inconsistent with security. The security of a system constantly evolves. Countermeasures introduced yesterday are no longer effective against tomorrow's attacks. Besides, combining security and safety is not an easy matter. The security of a critical system directly impacts its safety. Thus, ideal memory safety countermeasures must be compatible with safety. For instance, the detection of a security issue related to memory corruption must be highly configurable to switch to recovery routines that keep the critical device in a safe mode.

To summarize, integrating practical memory safety protection in life-critical medical systems is challenging. To be accepted, this thesis considers that security countermeasures should closely follow the previously exposed criteria such as Robustness, Performance, Space overhead, Modularity, Compatibility, Determinism, Practicality, and Safety to better fit life-critical software security. With an awareness of the criteria, the following section unfolds the thesis's approach to improve embedded device security.

Chapter 2. Approach

Approaches

This thesis aims to propose practical memory safety defenses adapted to life-critical medical systems. For this purpose, this section proposes consistent approaches with the problem statement in section 2.1 and the exposed criteria in section 2.2. However, as this thesis unfolds in the life-critical system field, it is relevant to work with a coherent system workbench. Such a system aims to model the behavior of a lifecritical device and serves as a security system workbench to evaluate the efficiency of security countermeasures. Unfortunately, as previously stated, with the lack of openness to research in the medical area, the existence of such a platform is less. Referring to section 2.1.1, the lack of openness to research does not encourage security improvements in medical devices. Indeed, there are almost no open-source medical devices, and it is therefore almost impossible to design dedicated defenses and assess their effectiveness. To fill this gap, this thesis proposes an open security-oriented system workbench platform that models the behavior of a life-critical device. The main goal of such a platform is to further allow the design and assessments of security countermeasures dedicated to safetycritical systems. More specifically, the system workbench is a wireless insulin pump. Such a system is considered as a life-critical medical system and can be simply modeled on offthe-shelf microcontrollers or FPGA. The details and the novelty of the system workbench are highlighted in Chapter 3. The platform is inspired by a survey on existing open platforms and existing insulin pump models.

Back to memory safety, the thesis's approach aims at following the criteria exposed in section 2.2. According to the state-of-the-art synthesis in section 1.4 and to achieve the best balance between robustness, overheads (time and size), compatibility, practicality, determinism, and safety, this thesis enforces that ideal memory safety protections involve both hardware and software. Hardware means that countermeasures require to either change a processor architecture, interface with a processor or add additional external independent hardware modules for security support. Software means that countermeasures require a dedicated toolchain such as compiler, libraries, binary instrumentation tools, and/or finally, real-time operating systems or bare-metal support.

To address software security, this work proposes two approaches. The first one assumes that both the hardware layer (processor) and all the software layers (real-time operating system, compiler, standard C libraries) can be modified to enforce dedicated security support. The second approach considers that most of the chips used in medical devices are fixed based on closed source processors. This unfortunately prevents any hardware architecture modifications. Therefore, the implementation of memory safety defenses is limited to the software layer, i.e. the real-time operating system, libraries, and the entire code generation toolchain. It should be mentioned that even in some cases, neither the compiler used nor the real-time system is accessible.

To fill the criteria exposed in section 2.2, both approaches are top-down and globally divided into two phases. A first phase (design-time) in which critical application developers access an inherently secure toolchain. This toolchain hides the security complexity to 2.3. Approaches developers allowing application code to be generated with security assets adapted to the hardware. The second phase (run-time) is the execution of the generated critical application that benefits from support provided by both hardware and software. The main goal of both top-down approaches is to simplify the integration of memory safety defenses to non-security experts and ensuring robust run-time protection. Secure Toolchain

Figure 2.1: Generative approaches

Referring to Figure 2.1, the first approach (1 in 2.1) provides security support from hardware to software. To ensure the finest tradeoff between robustness and performances, the run-time protection engine is rooted in hardware. As revealed in the state-of-the-art, data-flow integrity seems to be the finest security approach to tackle the memory safety issue. Thus, the run-time protection engine tracks sensitive data such as function pointers, return addresses, induction variables, and security-critical data to detect their violation.

When a violation happens, the run-time protection detects it, logs it, and maintains the system in a safe state. Of course, the run-time protection is deterministic and not based on randomness.

To be efficiently used, the hardware support is accompanied by a software toolchain.

This toolchain, used at design-time allows the developer to easily generate a secure code adapted to the hardware security support. Following section 2.1, providing a secure toolchain removes the complexity of security to developers while maintaining modularity and compatibility with the C standards. This first approach results in a framework called TrustFlow discussed in Chapter 4.

The second approach (2 in Figure 2.1) does not consider hardware modifications. It assumes that the latter is immutable and security features can only be implemented at Chapter 2. Approach the software layer. Since this approach has fewer degrees of freedom than the previous approach, it is likely to be less robust. However, this approach aims at demonstrating that it is still possible to integrate a certain level of security in critical applications without degrading the criteria.

As the first approach, the second approach is top-down (see Figure 2.1). To ensure a robust memory exploits protection, the software run-time environment approach should also tackle the memory safety issue at its root: the initial corruption of critical data.

Unfortunately, as revealed in the state-of-the-art in Chapter 1, tracking the data-flow entirely in software is costly. Thus, to not undermine the performance, this approach is more relaxed and focus on control-flow integrity. While this approach is less robust than pure data-flow integrity, it stills raises the bar for attackers.

Regarding the other criteria such as safety and determinism, the run-time environment aims at providing the same assets as the first approach without performing any change at the hardware layer. Of course, the secure run-time environment should be accompanied by a design-time software tool-chain with the same assumptions as approach 1. This second approach results in a framework called BackGuard discussed in Chapter 4.

To summarize, this thesis proposes three contributions. First, an open-source lifecritical medical device system workbench for security purposes. The main purpose of such a platform is to serve as a relevant system to integrate and further benchmark security solutions dedicated to life-critical medical devices. This contribution may assess both approaches 1 and 2. Second, this thesis proposes TrustFlow and BackGuard that follows two previously exposed approaches. One relies on both hardware and software and the other completely on software to ensure memory safety. These two contributions aim at providing a user-friendly framework where developers can easily integrate security in critical systems taking into account all the criteria outlined in section 1.1.3.

SecPump

Summary of the Chapter

This chapter presents SecPump a life-critical system workbench tailored for security assessments. Presently, medical devices are closed-source and protected by commercial constraints. These constraints prevent this thesis from performing attacks on these devices as well as implementing appropriate countermeasures. To fill this gap and conduct the approaches exposed in Chapter 2, this Chapter presents SecPump.

SecPump is an open wireless insulin pump model dedicated to security. The platform is specifically tailored for countermeasures development against the numerous security flaws related to medical devices. First, this chapter highlights the motivations of such a platform, its assets over existing work, and its interests for security. Second, the chapter details the functioning of the system and its various operating modes. The results show that SecPump is relevant enough to simulate the behavior of a classical insulin pump. Then, both hardware and software security vulnerabilities on such a platform are discussed and a set of memory safety exploit is showcased. These demonstrations are thereafter used to assess security countermeasures.

Motivation

To further anticipate the design of appropriate security protections that target lifecritical medical systems, this work requires a representative system workbench. Of course, such a system workbench should closely follow the assumptions highlighted in 1.1.1 and models the behavior of an off-the-shelf life-critical medical device. Unfortunately, most of the critical medical devices on the market are proprietary. They come with commercial constraints and intellectual property that even prevent this work to freely attack them, discloses vulnerabilities, and modify any components to integrate security features. To remind, currently, no specific bug bounty program [START_REF] Kuehn | Analyzing bug bounty programs: An institutional perspective on the economics of software vulnerabilities[END_REF] encourages security research on real medical devices.

Due to this lack of openness to research, the design of innovative security protection in medical devices is difficult to implement and to evaluate. Neither the software nor the hardware of existing devices on the market can be modified to accommodate innovation in the field of security. As a result, it seems that without a representative model, medical device security is not an easy matter for this academic thesis. Also, combined with the fact that real medical devices are expensive, it seems that studying their security is a challenge.

To address these issues and to further benchmark safe security protection this chapter proposes SecPump; a wireless medical device security system workbench. More specifically, SecPump is a platform that mimics the functioning of a real insulin closed-loop system. This thesis decided to model a wireless insulin pump because it is a critical system that has been actively developed and connected to various networks [START_REF] Lily | These Hackers Made an App That Kills to Prove a Point[END_REF][START_REF] Radcliffe | Hacking medical devices for fun and insulin: Breaking the human scada system[END_REF] over the last few years. Overall, an insulin pump is a consumer device often used outside of hospitals.

With fewer functionalities, it can be easily modeled on an off-the-shelf microcontroller with integrated wireless protocols. The main purpose of SecPump is thus to model the activity of a wireless insulin pump without requiring the purchase of expensive external mechanical components that are often not very useful in hardware or software security assessments.

In a second step, this work proposes to make SecPump open-source in the hope that it will be used in further security researches. Indeed, the platform aims at contributing to the awareness of security and the acceptance of new concepts compatible and maybe implementable in closed-sources systems. Overall, there is comparatively little information on the web regarding attacks that target critical embedded systems, rather than mobile and personal computers application. Although some methods of attacking personal computers and embedded systems are similar, implementing countermeasures on a critical system requires consideration of additional issues such as safety assessment and real-time constraints [START_REF] Bernsmed | Safety critical software and securityhow low can you go?[END_REF]. These constraints are not required for most other types of computing systems. Thus, such an open platform opens up new opportunities in the design of innovative security assessments dedicated to embedded systems. On the red-team side, SecPump can be used as a system workbench to show the impact of security vulnerabilities on a cyber-physical system. For instance, both software attacks (e.g., memory corruption, mal-3.2. Open Source Medical Devices

Open Source Medical Devices

Wireless insulin pumps are an excellent example of life-critical medical devices. These devices are used by both hospitals and individuals in the treatment of diabetes. More precisely, the purpose of these devices is to mimic the pancreas achieving fine-grained glycemic control. Emergent wireless insulin pumps are proved to be fairly effective at delivering perfect doses of insulin maintaining blood sugar at a correct threshold. Usually, a healthy, non-diabetic person has a blood glucose level of around 85mg/dL in the fasting period. When the latter eats a meal, sugar enters the bloodstream. As a result, the pancreas releases insulin so that the glucose in the blood is absorbed by the muscles to produce energy. The natural production of insulin by the pancreas lowers glycemia to keep it between 80 mg/dL and 120 mg/dL. With a type I diabetic, the pancreas is deficient and loses its ability to produce insulin. Thus, when a meal is taken, the blood sugar level does not decrease and can lead to health problems. Above 180 mg/dL the body starts to release glucose in the urine, and a patient is considered hyperglycemic when the glycemia exceeds 270 mg/dL. Although many insulin pump devices are proprietary, several models, academic implementations, and guidelines have been proposed so far [START_REF] Arney | Formal methods based development of a pca infusion pump reference model: Generic infusion pump (gip) project[END_REF]. This section reviews the existing open-source medical devices and studies their feasibility to serve as a platform for security assessments.

The Generic Infusion Pump (GIP) project [START_REF] Arney | Formal methods based development of a pca infusion pump reference model: Generic infusion pump (gip) project[END_REF] launched by researchers from the FDA [4], the Center for Devices and Radiological Health (CDRH), and the Office of Science and Engineering Laboratories provides several methods and guidelines in the design of critical infusion pump devices. Many documents from this project are open-source and aim at serving as a safety design reference model to identify several hazards in various medical infusion pumps. These documents are intended to be used by both academia and manufacturers. More precisely, it encourages life-critical devices manufacturers to refer to the guidelines early in their design process to validate basic safety properties.

Several works, particularly in the field of safety, have been carried out on the GIP project. An implementation of a formally verified infusion pump has even been made available by the University of Pennsylvania [START_REF] Arney | Formal methods based development of a pca infusion pump reference model: Generic infusion pump (gip) project[END_REF]. However, the latter is slightly different from the expectations of this work. First, the proposed model is a classical hospital infusion pump that is not wearable and generally not available to the general public like insulin pumps. Second, the proposed implementation is generic and hardware-independent, it runs on a complete Linux operating with virtual layers that exhibit deterministic infusion operations. This work is rather positioned in the emerging field of IoMT. It requires a wearable medical device model much more restricted than GIP. An ideal model would if possible be based on low power microcontroller(s) with a firmware written in bare-metal or based on a lightweight real-time operating system such as FreeRTOS [START_REF] Barry | Freertos[END_REF]. Finally, the GIP model does not consider the security issues related to the connection of a medical system. However, it seems that the IoMT is following a different trend [START_REF] Lily | Medical Devices Are the Next Security Nightmare[END_REF]. Increasingly more manufacturers are implementing network protocols in their devices [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF] to enable Chapter 3. SecPump remote access control and data gathering. As a consequence, an ideal security-oriented model should implement at least one wireless feature commonly integrated into IoT.

The Open-Source Syringe Pump library [START_REF] Wijnen | Open-Source Syringe Pump Library[END_REF] provides an open implementation of a syringe system based on Raspberry Pi along with RepRap 3-D printers plans. The main purpose of the Open-Source Syringe project is to provide a customizable inexpensive medical system for research purposes affordable by all. The major components of the system involve a Raspberry Pi, a stepper motor, and the mechanical parts such as a sliding screw and other pieces that should be printed in 3-D. Unfortunately, accessing a 3D printer, and buying certain parts to create a functional system is convenient. Moreover, buying or accessing a 3D printer can be expensive and/or time-consuming. To mostly focus on security aspects, this research requires a portable demonstrator without relying on external mechanical components. Although mechanical vulnerabilities are relevant to real medical devices, they are beyond the scope of this thesis. Finally, from a certain point of view, the open-source syringe project is much more aimed at students and researchers willing to learn how to build a medical device rather than performing security assessments. For instance, the open-syringe does not model the impact of a security vulnerability directly on the safety of the user's medical device.

The Open Artificial Pancreas project (openAPS) [START_REF] Melmer | Glycaemic control in individuals with type 1 diabetes using an open source artificial pancreas system (openaps)[END_REF] provides an open-source connected artificial pancreas using a Raspberry-Pi. This project, initially launched by Dana Lewis 3.2. Open Source Medical Devices in 2014, aims at automating insulin injection for diabetes using an open-source computer system that controls a commercial insulin pump. Originally, insulin injection using commercial pumps was achieved manually by diabetics. First, the latter had to prick itself to measure his/her blood sugar. Then, depending on the measurement, the diabetic had to self-inject an insulin bolus to bring his/her blood glucose back to an acceptable threshold.

Since this method is not the most practical for patients, Dana Lewis tried to improve it by creating one of the first closed loops systems to automate the process. Such a system involves four components displayed in Figure 3.2. The first component (1) is a wireless Continuous Glucose Monitor (CGM) placed under the skin that constantly measures a patient's blood sugar. The measured value is sent to a remote smartphone (2) via a wireless protocol so a patient can visualize it. Then, the smartphone sends the glucose measurements to an off-the-shelf Raspberry Pi computer (3) via Bluetooth. The Raspberry Pi receives the Bluetooth data from the smartphone and processes it to define the amount of insulin to inject so that the patient blood sugar remains within a pre-defined targeted blood sugar level. Finally, once the insulin quantity is computed by the Raspberry Pi, it is transmitted to a commercial pump (4) via a radio protocol to process the injection.

The injection regulates the glycemia of the patient closing the loop of the whole system. is really "plug-and-play", it either requires printing additional parts, buying expensive components or spending time implementing the model. Furthermore, it seems that the existing open-source cyber-physical systems are more appropriate for learning how to build a life-critical system than for security assessments thereof. Besides, most of the presented models do not integrate the latest low-power and portable IoT wireless technologies such as Bluetooth Low Energy, LoRa, etc. Consequently, they are not well suited to model recent IoMT devices and consider a wide range of security threats.

To perform accurate security assessments, this work requires a portable open-platform that closely models a medical device functioning with fewer constraints. In other words, such a demonstrator should be implemented on an inexpensive off-the-shelf microcontroller and/or an FPGA and should not rely on any additional sensors, mechanical components, and/or interactions with a real diabetic patient. Only the most security-sensitive components relevant to the purpose of this thesis should be supported to conduct the study. Finally, an appropriate IoMT medical device model should implement at least a low power wireless feature to communicate.

SecPump

SecPump

Presently, no open-platform offers a portable, security-oriented, hardware-software based model implementation of a wireless medical device. Thus, to further model cyberthreats on life-critical devices, this chapter proposes SecPump a wireless infusion pump system workbench primarily based on an STM32 Nucleo F446-RE board.

A wireless pump model

The design of SecPump is inspired by the OpenAPS [START_REF] Melmer | Glycaemic control in individuals with type 1 diabetes using an open source artificial pancreas system (openaps)[END_REF] closed-loop system. More precisely, SecPump is only the insulin pump of the whole system. To operate it requires a diabetic who is simulated by the Raspberry Pi. To represent the physical link between a theoretical diabetic and the wireless pump, SecPump is connected via the serial port to the Raspberry Pi. The Raspberry Pi models the glycemic regulation in response to insulin injection performed by the pump. The relationship between blood insulin levels and glucose is based on Bergman's differential equations. These will be detailed further Chapter 3. SecPump in the Chapter.

To regulate the simulated diabetic glycemia, SecPump integrates a Continuous Glucose Monitoring routine that performs glucose requests to the Raspberry Pi at regular intervals. Then, the CGM sends the glucose measurements to an external smartphone and updates the internal controller routine values. According to the operating mode (detailed in section 3.3.2), the controller routine injects (sends) an amount of insulin to the Raspberry Pi to regulate glycemia.

SecPump software model

Currently, SecPump proposes to regulate diabetics' glycemia using two operating modes:

a manual mode and an automatic mode. Simply, the manual mode requires a smartphone.

The latter should connect to the pump using Bluetooth Low Energy (BLE) protocol. Once the connection has been established, the CGM routine of the pump sends the simulated measured blood glucose at regular intervals to the smartphone. According to the measured glycemia, the patient can decide to manually trigger an insulin bolus injection by the pump. The amount of insulin to inject by the pump is sent through BLE from the smartphone. Then, the pump simulates the injection to the human glycemia simulator using the serial interface. Conversely, in automatic mode, SecPump regulates the blood glucose autonomously without requiring any manual bolus injection from the diabetic. Changing from one mode to another can be achieved using a BLE command. The functioning of SecPump and its modes are described in the following sections.

Manual mode

The manual mode requires the SecPump's user to monitor the glycemia from its smartphone and inject insulin accordingly. In other words, the manual mode can be compared to an open-loop regulation system such as in Figure 3.4.

Human Body Simulator U(t) D(t) G(t)

.4: Open-loop regulation system

In manual mode, SecPump regularly measures blood glucose through the serial interface with the diabetic simulator (Raspberry Pi). This value, G(t) in Figure 3.9, is sent via BLE to a remote smartphone. The diabetic can thus proactively track glucose highs and lows and perform an insulin bolus injection U(t) (in Figure 3.9) to regulate glycemia.

Upon receipt of a BLE insulin bolus request, the pump triggers the sequence displayed in Figure 3.5. Upon reception, the controller checks both glycemia and insulin injection history. These checks ensure that the user is not trying to self-inject insulin with a low blood sugar level or a lethal dose. Finally, the insulin value is transmitted to the Raspberry Pi. This simulates a real insulin injection. Regarding the diabetic side, the Raspberry Pi simulates the absorption of insulin and decreases glycemia accordingly.

SecPump

CGM routine

Human body modeling Modeling the balancing feedback between insulin

and glucose is one of the most important parts of the platform. Although this thesis is not related to research in medicine, the balancing feedback must be representative. Indeed, to be efficiently used as a system workbench for security and safety assessments, SecPump should accurately model the insulin/glucose kinetics.

Unfortunately, modeling the blood glucose relation using software is not an easy matter.

While several mathematical models have been proposed and evaluated so far [START_REF] Fisher | A Semiclosed-Loop Algorithm for the Control of Blood Glucose Levels in Diabetics[END_REF], [START_REF] Roy | Mathematical Models of the Metabolic System in Health and in Diabetes: Dynamic Modeling of Exercise Effects on Plasma Glucose and Insulin Levels[END_REF],

none of them can reproduce the human body with 100% accuracy. One of the most famous mathematical modelization of the glucose-insulin relation is the modified Bergman's minimal model [START_REF] Roy | Mathematical Models of the Metabolic System in Health and in Diabetes: Dynamic Modeling of Exercise Effects on Plasma Glucose and Insulin Levels[END_REF]. This model is usually used to simulate the glucose-insulin kinetics for a diabetic patient using four coupled differential equations stated below:

Chapter 3. SecPump dG(t) dt = -(p 1 + X(t))G(t) + p 1 G b + D(t) (3.1) dX(t) dt = -p 2 X(t) + p 3 (I(t) -I b ) (3.2) dI(t) dt = -p 2 I(t) + U (t) V I (3.3) dD(t) dt = -d rate D(t) (3.4)
With the parameters described in Table 3.1. The decay rate of blood insulin.

d rate min -1
The decay rate of the meal disturbance

The discussion regarding the exact details of theses parameters is beyond the scope of the thesis study. For more in-depth details, this thesis refers the reader to more advanced publications in the field of medicine [START_REF] Roy | Mathematical Models of the Metabolic System in Health and in Diabetes: Dynamic Modeling of Exercise Effects on Plasma Glucose and Insulin Levels[END_REF][START_REF] Bergman | Lilly lecture 1989. Toward physiological understanding of glucose tolerance. Minimal-model approach[END_REF][START_REF] Friis-Jensen | Modeling and Simulation of Glucose-Insulin Metabolism[END_REF] that inspired the presented implementation.

All these equations are integrated into the external Raspberry Pi using Python. The modeling of blood glucose is at the heart of equations ( 1) and (3). The integral of equation

(1) gives the glucose concentration over time that is transmitted to SecPump. Of course, this equation is coupled with the disturbance equation ( 4) and the Active Insulin Effect equation [START_REF] Chiang | Fog and IoT: An Overview of Research Opportunities[END_REF]. In more detail, equation (4) represents a patient's meal intake, and thus the perturbation induced on the blood glucose level given by equation (1). Finally, equation

(3) models the insulin concentration kinetics over time. This equation depends on U(t) the function that usually models the insulin produced by the pancreas. However, in this study, U(t) is replaced is the output of the artificial pancreas: SecPump.

As the aim of the external Raspberry Pi is to simulate a diabetic patient, several 3.3. SecPump assumptions about the differential equations are outlined above. Initially, the Raspberry Pi simulates an untreated diabetic patient. As a result, it considers that the blood sugar of the patient and its basal value is extremely high as no insulin is produced. This leads to the following initial conditions:

G(0) = G b = 280mg/dL (3.5) I(0) = I b = 0 (3.6) X(0) = 0 (3.7)
With these parameters [START_REF] Friis-Jensen | Modeling and Simulation of Glucose-Insulin Metabolism[END_REF]:

p 1 = 0.028735min -1 (3.8)
p 2 = 0.028344min -1 (3.9)

p 3 = 5.035e -5L/(min 2 .mU ) (3.10)
p 4 = 0.05min -1 (3.11)

V I = 12L (3.12)
The initial state of the blood glucose simulation is displayed in Figure 3.6. The measurements are taken over a simulated period of 24 hours considering that the theoretical patient is fasting. The blue curve represents SecPump in manual mode, no insulin is injected. The red curve represents the blood glucose level of the simulated diabetic patient.

Figure 3.6: Manual mode initial state

In Figure 3.6, the blood glucose level is extremely high. According to the initial assumptions, no insulin is produced by the diabetic patient and no insulin is injected by Chapter 3. SecPump SecPump. As a consequence, the Raspberry Pi simulates the glucose that remains within the blood and is not absorbed by the human muscles.

To lower the blood glucose level, an injection sequence should be triggered using BLE.

By first considering the system with no perturbations (no meals, D(t)=0), a bolus step response of the whole system with 17mU/min of insulin is displayed in Figure 3.7.

Figure 3.7: Manual mode step insulin injection

According to Figure 3.7, the step response reaches a new steady-state of around 100 mg/dL in two hours. This steady-state is within the blood glucose limits of a healthy person without excessing 100 mU/min insulin injection rate [START_REF] Friis-Jensen | Modeling and Simulation of Glucose-Insulin Metabolism[END_REF]. These measurements validate that the whole system operating in manual mode is reasonable for modeling a real insulin pump.

Unfortunately, the manual mode does not fully simulate an artificial pancreas. The two previous graphs result from measurements taken without meal disturbances. When random disturbances due to meal intake are introduced by the diabetic simulator, the blood glucose level in the human body still rises to 200 mg/dL (see Figure 3.8). In Figure 3.8, the glycemia simulator is programmed such that it introduces disturbances at mealtimes of 8:00 am, 1:00 pm and 7:00 pm respectively. These disturbances follow the differential equation ( 4) with a d raterandom valuebetween0.5and10mg/(dL.min) [START_REF] Fisher | A Semiclosed-Loop Algorithm for the Control of Blood Glucose Levels in Diabetics[END_REF].

Figure 3.8: Manual mode meal perturbation simulation

Of course, to better regulate the blood sugar, the diabetic can manually adjust the pump injection rate according to each meal. The diabetic can also use an algorithm such as [START_REF] Melmer | Glycaemic control in individuals with type 1 diabetes using an open source artificial pancreas system (openaps)[END_REF] on the smartphone to control the pump remotely. However, better regulation can be automated and practically implemented within the model.

SecPump

Automatic mode

To achieve fine-grained insulin regulation on the model, SecPump proposes an automatic mode that regulates blood sugar using an integrated PID. This integrated PID is activated when switching from manual mode to automatic mode. It requires a target value at which the pump should maintain the patient's blood glucose. As a whole, the automatic mode operates as a closed-loop regulation system displayed in Figure 3.9.

Human Body Simulator U(t) D(t) G(t) PID Controller

Error Setpoint

SecPump

Figure 3.9: Closed-loop regulation system

The SecPump system measures blood glucose from the Raspberry Pi simulator. Using the setpoint and the measured glucose the PID determines the amount of insulin to inject within the system. More precisely, the main sequence of the pump in automatic mode is displayed in Figure 3 The automatic mode is driven by two routines. First, the pump controller frequently checks the value of the blood glucose updated by the CGM routine. Glucose measurements are added to a pump's internal measurement history. According to the measured values the controller determines the error between the blood glucose and the setpoint. From this error, the PID injects a certain amount of insulin to lower the blood glucose.

Chapter 3. SecPump

PID

Regarding the insulin regulation, the output of the PID (output of the pump) has a direct impact on equation (3) of the Bergman differential equations. As these equations are non-linear, we developed a simple Python interface based on the Jupyter framework to manually tuned the coefficients of the PID. This interface makes it possible to graphically model the behavior of the controller before programming the pump. In this thesis, the PID coefficients of SecPump are tuned empirically such that the blood glucose stimulated by the human simulator stays between 60 and 180 mg/dL [START_REF] Friis-Jensen | Modeling and Simulation of Glucose-Insulin Metabolism[END_REF]. We are aware that there are several techniques to determine the values of a PID accurately, even for non-linear systems. However, they are beyond the scope of this thesis. It should be mentioned that this can be the subject of ongoing work and further contribution to the pump. Also, the PID implemented in SecPump follows the Oral Glucose Tolerance Test (OGTT) [START_REF] Care | Classification and Diagnosis of Diabetes: Standards of Medical Care in Diabetes-2020[END_REF] by ensuring that blood glucose of the diabetic simulator drops bellows 140 mg/dL at least 2 hours after meal intake.

The real-time functioning of the PID implemented in SecPump is displayed in Fig-

SecPump variants

To remind, in Chapter2 section 2.3, two approaches are proposed regarding the implementation of security in life-critical devices. One approach is hardware-software oriented and the other completely software oriented. Thus, to perform appropriate security assessments, several variants of SecPump are developed accordingly. The second variant of SecPump, SecPump-RT-BLE is just an enhancement of SecPump-BLE. While the previously exposed variant's sequences are orchestrated by a finite state machine, this version is based on the real-time system FreeRTOS [START_REF] Barry | Freertos[END_REF]. Simply, all routines of SecPump-BLE are implemented and scheduled by the FreeRTOS operating system.

On both SecPump-BLE and SecPump-BLE-RT, only the software layer of the implementation is open source. While it allows performing both hardware and software attacks demonstration on the platform, the integration of security is more restricted. Indeed, the ARM architecture is proprietary, it does not allow the integration of invasive hardware security blocks into the processor core. Regarding previous approaches discussed in section 2.3, both variants are mostly fitted for software-based security extensions, so the second approach.

Finally, SecPump RISC-V is an adaption of SecPump-BLE ported to run on a RISC-V processor using the open-source port on a Digilent Xilinx ARTY-35T provided by SiFive [START_REF] Sifive | SiFive RISC-V port[END_REF]. As the FPGA does not support wireless connectivity, any communication with the pump is performed through the serial interface. In comparison with the other variants, SecPump RISC-V is fully open-source from hardware to software. Indeed, unlike the ARM architecture, the RISC-V architecture running on the Digilent Xilinx ARTY-35T is open-source. It allows modifying the hardware layer to integrate security features and as the previous version, all the software layers as well.

Chapter 3. SecPump

Security Assessments

Above all, SecPump is a life-critical system workbench dedicated to security assessments. Usually, when performing security assessments on a system it is important to define the context, the threats and their impact, the scenarios of attacks, the risks and the countermeasures. As SecPump is a cyber-physical system, it is vulnerable to the same as known attacks as other existing embedded systems. However, as SecPump models a life-critical medical device, the consequences of related security vulnerabilities are a little different. Indeed, an attack can directly impact the safety of the system and even cause irreversible health damage to the user. The interesting point with security issues on lifecritical devices is that they can cause unexpected safety issues that were not considered during the design. As part of the SERENE-IoT project Work Package 2 (WP2), we carry out an in-depth security study of a wireless pump inspired by the EBIOS method [START_REF] Anssi | Ebios-expression des besoins et identification des objectifs de sécurité[END_REF].

While insulin pumps are not only subject to memory safety issues, this section focuses on it to stick to the research direction of the thesis. The section 3.4.1 focuses on the memory safety threats of such a platform. It showcases a scenario of attack on the pump and the according risks. Finally, section 3.4.2 is an opening to hardware security.

Software Threats

At the software level, several modules of the pump can be targeted by an attacker. Regarding memory safety, the most critical software module remains the BLE connection.

A memory safety vulnerability in the wireless module leaves the pump open to a remote attack. Conversely, without a wireless connection, memory safety issues can be considered less threatening.

Based on the memory safety threats linked to the connection of such a system to the network, we have developed several attack scenarios. To do so, an intentional stackbased buffer overflow bug is introduced in the BLE packet parser by removing a common boundary check in the SecPump software. This introduced vulnerability model a software bug as it is possible to find in existing wireless pumps on the market [START_REF]Hospira Multiple Products Buffer Overflow Vulnerability[END_REF][START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF]. Two memory exploits are developed accordingly to demonstrate the impact of such security vulnerabilities.

The first exploit is a control-flow attack. It leverages the buffer overflow vulnerability to overwrite a return address on the BLE's routine stack. The exploit diverts the execution flow on an injected sequence of address instructions scattered into the SecPump code address space. This attack breaks the control-flow graph of the insulin pump by combining both Return-Oriented Programming [START_REF] Checkoway | Return-oriented programming without returns[END_REF] and Jump-Oriented Programming techniques [START_REF] Bletsch | Jump-Oriented Programming : A New Class of Code-Reuse Attack[END_REF]. The executed gadget chain mimics an "insulin injection" sequence and transmits the insulin amount to the diabetic simulator using the serial interface. The impact of the attack is displayed in Figure 3.12. The blue graph displays the amount of insulin injected by the pump in real-time, the red graph shows the simulated blood glucose level, the black curve shows the concentration of insulin in the patient's blood and the green curve shows the effect of active insulin. One can observe that the attack is performed at 3.4. Security Assessments around 4 pm in the graph. At this time, the controller injects up to 300 mU/min amount of insulin inducing a significant drop in glucose and a significant lethal increase of insulin in the diabetic.

Figure 3.12: Remote code execution in SecPump

The second exploit is a non-control data attack. As the previous attack, this exploit leverages the same buffer overflow to perform arbitrary writes in the pump memory. Instead of overwriting a return address stack, this attack triggers a data pointer on the stack that indirectly modifies the amount of insulin to inject to the human body. Unlike the previous control-flow attack, this data attack does not break the control-flow of the application but results in the same significant threats and results displayed in Figure 3.12.

Of course, these attacks are feasible because the demonstrator does not implement any specific security protections. However, they can be reuse to access further security protections. Also, these attacks showcase a worst-case scenario that may impact a critical wireless device.

Hardware Threats

Hardware attacks are fully applicable to SecPump. Indeed, by having physical access to a device an attacker may achieve a wide range of attacks. For instance, by using passive and/or active hardware attacks such as side-channel and fault injection an attacker leverages both the physical properties and the physical access to the device to leak/modify sensitive assets such as cryptographic keys [START_REF] Kazemi | Hardware security evaluation platform for mcu-based connected devices: Application to healthcare IoT[END_REF]. While the pump is developed without any particular security countermeasures, its cryptographic module and other sensitive parts may be jeopardized by hardware attacks. As for software attacks, SecPump is the perfect target for research in lightweight cryptography that should be robust to hardware attacks Chapter 3. SecPump and integrated into constrained critical systems [START_REF] Aerabi | Design Space Exploration for Ultra-Low Energy and Secure IoT MCUs[END_REF].

Also, hardware attacks can target both the control-flow and the data-flow of an application. This causes undefined code behavior leading to both security and safety issues.

The interesting fact with hardware attacks is that it induces disturbances into the system. These disturbances result from attacks but can also be due to interactions with the environment, which is the case for life-critical medical systems that should operate under any conditions. For instance hardware attacks can be used to induce system failures such as desynchronizing the Real-Time Clock of the pump, inducing false positives/negatives during safety checks, flipping bits from the RAM and registers, and even simulates peripheral errors (CGM for instance). As a result, SecPump is a suitable platform to also assess novel safety protections and recovery mechanisms. For more in-depth details about hardware security assessments on life-critical medical systems, this section refers to interesting works that used SecPump as a security system workbench [START_REF] Kazemi | Hardware security evaluation platform for mcu-based connected devices: Application to healthcare IoT[END_REF].

3.5. Comparison with other works

Comparison with other works

This work also proposes to release SecPump as an open platform for the community.

We believe that such a platform is a great asset and may encourage further researches regarding life-critical devices' security. This section compares SecPump to the related work exposed in section 3.2. It should be mentioned that the purpose of this contribution is not to compete with the related work, on the contrary, SecPump proves to be a complementary platform with a focus on security. Whether they are open-source, the financial costs to get a functional demonstrator, if it is simple to set up the demonstrator (practicality), whether the existing work handles wireless features, and finally if the platform is well suited for security assessments.

According to Table 3.3, three works offer a fully open-source IoT platform; Open-Syringe [START_REF] Wijnen | Open-Source Syringe Pump Library[END_REF], SecPump, and the University of Pennsylvania that provides an implementation of a Generic Patient Controlled Analgesic infusion pump that follows the GIP guidelines [START_REF] Arney | Formal methods based development of a pca infusion pump reference model: Generic infusion pump (gip) project[END_REF]. They mostly provide complete code to implement a functional medical device. In comparison, openAPS [START_REF] Melmer | Glycaemic control in individuals with type 1 diabetes using an open source artificial pancreas system (openaps)[END_REF], provides a Raspberry-Pi based artificial pancreas that controls a commercial insulin pump. Unfortunately, while the artificial pancreas insulin regulation algorithm running on the Raspberry-Pi is fully open-source, the commanded pump is not, making the whole system not entirely available.

Price is also a limiting acceptance factor for academic research. According to [START_REF] Wijnen | Open-Source Syringe Pump Library[END_REF],

a commercial pump can cost up to $5000 which is not always affordable. Also, even if the openAPS project is based on a Raspberry-Pi that costs around $50, it communicates with a closed-source commercial insulin pump that costs around $700. Both open-syringe and SecPump are affordable. The open-syringe project claims that the syringe can be built by spending less than $100 including, Arduinos, the Raspberry-Pi, and printing the 3D mechanical parts. However, it does not include the 3-D printer price. Regarding SecPump, the BLE-RT version only requires an off-the-shelf STM32 F446-RE with the Chapter 3. SecPump BluNRG extension board. The total cost less than $30. However, the implementation price of SecPump rises when the platform is implemented on an FPGA. For instance, the SecPump RISC-V version requires a Xilinx Digilent Arty 35-T FPGA that costs about $130. Finally, the GPCA implementation [START_REF] Arney | Formal methods based development of a pca infusion pump reference model: Generic infusion pump (gip) project[END_REF] provides a generic code that is not tied to any specific hardware. According to the project, it should be ported/adapted to a real infusion pump hardware or a microcontroller.

For practicality, Table 3.5 excludes the commercial pumps. They are supposedly not requiring any manual implementation to work. The term practicality in Table 3.5 specifically targets the ease of implementation of an open platform to quickly perform primary technical security assessments. GIP provides many clear design documents for life-critical system developers. However, it does not provide an implementation tied to specific hardware to begin security assessments quickly. Thus, to perform security assessments, a primary step is to develop a prototype or adapt the specifications. Also, in comparison with SecPump, the GPCA implementation is more safety-oriented than SecPump, but it does not model the human body interactions. In addition to purchasing the components, both Open-Syringe and openAPS requires several steps to reach a functional demonstrator.

For instance, Open-Syringe requires the printing of several 3D parts with the assembly and connection of several motors. Unfortunately, not everyone possesses a 3D printer.

On the other hand, openAPS requires a compatible commercial insulin pump with the correct firmware version to be connected with the Raspberry Pi. In comparison, SecPump is more practical, it does not require any mechanical parts to be assembled, it only needs the open-source code to be compiled and flashed to an off-the-shelf microcontroller.

When dealing with security in IoT, connectivity is an important concern. Almost all the medical devices in Table 3.5 integrates a wireless communication protocol. This commonality is a great advantage for security research. Due to the IoT, embedded systems may be increasingly connected to the network and exposed to various new attack vectors.

Researchers should be able to work on these protocols to improve their security and find better ways to integrate them along with critical applications. The variety of wireless features offer diversity in attacks targeting protocols.

Finally, regarding security, OpenAPS and commercial pumps come with commercial constraints that prevent attackers to freely attack them. Only the Raspberry Pi of the OpenAPS project can be targeted. On the other hand, GIP aims at improving secure design in medical systems providing open-source methods and guidelines. However, GIP is not an implemented platform tailored for security assessments. Finally, Open-Syringe is not security-oriented. The framework aims at teaching how to build open-source medical devices. However, it should be noted that Open-Syringe has been adapted in software security works to assess the robustness of control-flow integrity countermeasures [START_REF] Abera | C-FLAT: Control-FLow ATtestation for Embedded Systems Software[END_REF].

3.6. Conclusion

Conclusion

This chapter introduces SecPump, a new open medical device platform tailored for security assessments. Presently, medical devices are closed source and protected by commercial constraints. This lack of openness to research makes it difficult to perform security assessments on these types of devices. Unfortunately, commercial constraints do not protect medical devices from security threats. It has been discovered that these devices are highly vulnerable to various cyber-attacks ranging from data theft to lethal security exploits [START_REF] Lily | Medical Devices Are the Next Security Nightmare[END_REF].

To conduct relevant security contributions in the field of life-critical devices, this thesis requires a representative model to work with. Unfortunately, after reviewing the state-ofthe-art, we did not find a completely open-source platform that models a wireless insulin pump at a lower cost, and that is tailored for security and safety assessments. As a result, this chapter proposed SecPump, a security-oriented wireless insulin pump system workbench that mimics the behavior of a real insulin pump. SecPump requires an offthe-shelf microcontroller or FPGA and is connected to an external Raspberry Pi that simulates the behavior of a diabetic's glycemia. More precisely, the Raspberry Pi simulates the insulin-glucose kinetics of a diabetic following the extended Bergman minimal model [START_REF] Bergman | Lilly lecture 1989. Toward physiological understanding of glucose tolerance. Minimal-model approach[END_REF]. SecPump interacts with the Raspberry Pi model by acting as an artificial pancreas. It regulates the insulin of the simulated diabetic thanks to a custom simple PID controller. The resulting implementation demonstrates that the PID can keep the insulin level of a diabetic within an acceptable range passing the OGTT test. We consider these measurements sufficiently representative of a real system to perform various security assessments.

As the second step, some security threats and scenarios in relation to the thesis are showcased on the platform. Two intentional memory safety vulnerabilities are introduced and exploited on the pump. The result shows that a simple linear buffer overflow vulnerability in the wireless communication protocol of the pump can induce several security and safety issues. These exploits are not new and follow the attack techniques widely explored in the state-of-the-art. However, they aim at being further reused to assess the approaches highlighted in 2.3. Regarding hardware security, SecPump is suitable to serve as a system workbench for both attacks and defenses. However, the study of hardware-related security issues is considered out of the scope of this thesis.

Motivation

Recent studies revealed that many critical Internet of Medical Things (IoMT) devices on the market are vulnerable to intrusion and software exploits [START_REF] Lily | Medical Devices Are the Next Security Nightmare[END_REF]. For instance, in 2017, the CVE-2017-12718 [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF] revealed several buffer overflow vulnerabilities allowing remote code execution on commercial infusion pumps. This case demonstrates that today's embedded IoT systems are beginning to face the same type of attacks as servers and personal computers. However, in the case of an infusion pump, a software exploit can directly threaten a patient's life. Unfortunately, as manufacturers are increasingly connecting devices to the Internet without sufficient security measures, serious security issues such as CVE-2017-12718 are expected to grow in the coming years.

According to both Chapter 1 and 2, one possible reason for this poor security trend comes from the fact that time-to-market, innovative features, and costs often take precedence over the integration of security. Also, another potential reason is that manufacturers of embedded applications lack security experts [START_REF] Ventures | Cybersecurity jobs report[END_REF]. Of course, healthcare manufacturers are well trained about safety issues and various hazards in medical devices for decades. Many medical devices on the market have been validated by recognized institutions [4] and to date are very safe. However, healthcare manufacturers are less aware of cybersecurity issues. Indeed, connecting a medical device to the network is a relatively recent trend. Exposing wireless devices to the Internet raises new cybersecurity issues that manufacturers were not confronted with in the past. The integration of security in embedded devices is a difficult task, and without security expertise, the design and the integration of the latter are usually poorly achieved.

In contrast, when a new critical device is released, hackers try to find programming errors to exploit them. One of the most common weaknesses is a memory corruption vulnerability. Such vulnerabilities give an attacker the ability to inject arbitrary code into the application at execution-time and divert its execution flow. Considering a life-critical medical device, such attacks can give the hacker the ability to modify life-critical values harming a patient's life [START_REF] Newman | A New Pacemaker Hack Puts Malware Directly on the Device[END_REF]15,[START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF]37].

Interestingly, regarding memory exploits, Chapter 1 of this thesis revealed an abundant state-of-art of effective protections. However, despite all the efforts that have been made to enforce memory safety, it seems that emergent wireless medical devices are still vulnerable to a wide range of memory exploits. For instance, [START_REF]Hospira Multiple Products Buffer Overflow Vulnerability[END_REF][START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF] found multiple code injection attacks allowing remote code execution on commercial infusion pumps. These code injection attacks revealed that the system did not possess even the most basic memory safety mitigations highlighted in the state-of-the-art. Security is an important concern for critical medical devices. They are in direct interaction with the human body and may cause irreversible harm in case of a security breach. Knowing the existing state-of-the-art defenses, manufacturers should have implemented at least one of them in critical devices.

Unfortunately, this is often not the case. As extensively discussed in Chapter 2, several factors are limiting the acceptance of memory safety protection in life-critical devices:

1. The time-to-market dynamic imposed by IoT is incompatible with advanced and Chapter 4. TrustFlow complex security tests that are time-consuming. Manufacturers want to release new innovative devices full of features to get to the market first.

2. Life-critical device manufacturers lack security resources [START_REF] Ventures | Cybersecurity jobs report[END_REF]. While they have the necessary resources concerning safety issues, wireless features expose critical devices to new attacks that they were not confronted with in the past.

3. Many concepts offer an incomplete defense [START_REF] Szekeres | Sok: Eternal war in memory[END_REF][START_REF] Davi | Hafix: Hardware-assisted flow integrity extension[END_REF]. Most of the CFI solutions provide either backward-edge or forward-edge protection. So an attacker can always attack forward-edges when backward-edges are protected and vice versa. As medical devices may be life-critical, they require complete protection.

4. Memory safety is a trade-off between the execution-time cost and the accuracy of the protection. It is often considered that memory protection inducing more than 5% execution-time overhead will never be accepted by manufacturers [START_REF] Szekeres | Sok: Eternal war in memory[END_REF]. Unfortunately, a lot of research work does not take this constraint into account [START_REF] Castro | Securing software by enforcing data-flow integrity[END_REF].

5. Most of the hardware-based countermeasures lack software support [START_REF] Szekeres | Sok: Eternal war in memory[END_REF] needed to enable them with minimal developer effort. As long as developers have to rewrite some parts of the software by hand, security solutions may be unpractical and hardly accepted.

6. Among all the protections, the state of a system after detecting an attack is never tackled. Detecting an attack is only the first step, the second step is to move the system to a safe state that does not impact the users' safety. None of the existing countermeasures exhibits innovative techniques to recover from memory attacks.

7. Finally, according to section 1.4, many security defenses, and concepts break the C programming language's modularity and portability [START_REF] Szekeres | Sok: Eternal war in memory[END_REF]. They require an application code to be instrumented afterward. This is not modular and even impractical in production software development environments. It forces developers to perform security tests at the end of a system's development phase. Besides, instrumented codes are often not compatible with non-instrumented third-party libraries.

To summarize, effective memory safety protection for life-critical embedded systems should closely follow the criteria listed above and in section 2.2 to have a chance to be integrated into medical devices. To fill this gap, this Chapter presents TrustFlow, a practical framework for memory safety in critical systems. Trustflow aims at keeping a sufficient tradeoff between simplicity, security, safety, and performances. TrustFlow is designed to provide fine-grained control-flow integrity support using data-flow integrity.

The main contributions of this Chapter are summarized below:

• TrustFlow environment, an innovative hardware design that can prevent, detect, and treat memory-based exploits at the data granularity. TrustFlow is an enhanced shadow stack (trusted memory) interfaced with a RISC-V processor pipeline.

Motivation

• TrustFlow framework, an innovative software toolchain able to generate secure code for the TrustFlow environment. The toolchain provides several controlflow integrity levels. The TrustFlow framework integrates a static analyzer that can determine the security cost of an application before its implementation on real hardware.

• A security evaluation of the TrustFlow framework based on the RIPE benchmark suite.

• A benchmark of the TrustFlow environment that exposes: the memory footprint of real representative critical applications, the execution-time overhead induced by TrustFlow using CoreMark [START_REF] Gal-On | Exploring CoreMark™ -A Benchmark Maximizing Simplicity and Efficacy[END_REF] benchmark suite, and the hardware cost of our implementation.

Approach

As TrustFlow deals with life-critical embedded devices, it follows the assumptions exposed in section 1.1.3. To remind, here are the major assumptions concerning the design of medical applications and the attacker's capabilities that the TrustFlow framework considers in this Chapter. Critical software assumptions: TrustFlow assumes that critical embedded systems mostly follow "The Power of Ten Rules for Developing Safety Critical Code" [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF][START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF]. These guidelines are not limited to but mostly forbid:

1. Dynamic memory allocation after initialization: the use of dynamic memory allocation with "malloc" introduces memory fragmentation and potential memory leakage (dangling pointers). The usage of dynamic memory allocation is nondeterministic and thus cannot be safe.

More than one level of pointer dereferencing:

The use of pointers is one of the major sources of programming errors, safety, and security issues. Although their use is practical, it must be minimized and restricted to the smallest scope as possible.

Usage of recursion and goto statement: recursion introduces cycles into control-flow

graphs that complicate the verification task of static analyzers. Besides, it is not an easy matter to cover all the tests to determine the upper bound of a recursive function. As a consequence, recursion can induce prohibitive unexpected large usage of stack memory in life-critical systems.

Function pointers:

The use of function pointers is discouraged according to the power of ten rules. Indeed, function pointers prevent static analyzers to prove the absence of recursion. Also, they restrict the types of checks that can be performed by static analyzers. The rules claim that the use of function pointers should be justified if used. According to the reviewed rules [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF], it seems that "constant function pointers, for instance, stored in lookup tables, pose no risk to safe execution or code analysis".

Function pointers are thus considered by the TrustFlow framework.

Threat model assumptions:

As this work focuses on memory corruption, it assumes that executed critical software may contain software bugs such as buffer overflows that can be turned into successful exploits. To be more precise, this work assumes that the attacker is powerful and may corrupt any in-memory data they want, either locally (on the interface of the embedded system) or remotely (through a communication protocol).

Thus, this threat model considers software attacks that are performed at execution-time with the following assumptions:

1. The running critical application software is statically verified and does not contain any malware. We consider that the attacker possesses the firmware and can find all vulnerabilities. However, the application code is immutable, the attacker cannot modify it nor upload a malicious process into the application data-space before triggering a successful memory exploit. and not physically on the system. Hardware attacks can also be used to learn how the system operates. The threat model has no problem with this. In 1, it already considers that an attacker possesses the firmware code and exploitable vulnerabilities.

The aim of TrustFlow is not to obfuscate or complicate the vulnerability research process, but to accept vulnerabilities and prevent successful exploits.

3. Software attacks such as row-hammer and cache side-channel attacks are considered out of the scope of the study.

Approach overview:

To address the criteria exposed in section 2.2, TrustFlow follows the top-down approach proposed in section 2.3. Unlike most existing defenses [START_REF] Szekeres | Sok: Eternal war in memory[END_REF], this approach tackles the memory safety issue from initial software design-time to its execution on the hardware. This thesis truly enforces that security should be integrated as early as possible in the software design process with simple tools that require minimal human efforts. Then, during execution-time, the security assets enforced by the software should be reinforced by hardware primitives.

: TrustFlow top-down approach

In Figure 4.1 the top-down approach is divided into two phases. First, at executiontime, the application is protected in a secure environment that provides hardware-based data-flow integrity. The secure environment assumes that the executed low-level program may contain any kind of memory bug that can be turned into an exploit. Taking this into account, the hardware extension tracks the integrity of both control-flow and non-control sensitive data. If sensitive data is maliciously corrupted, the safe environment detects it, logs it, and heals the corrupted data without impacting the users' safety.

Chapter 4. TrustFlow

To be efficient, the secure environment must identify sensitive data-flow. In the topdown approach, the sensitive data-flow is identified at design-time thanks to a secure toolchain and secure libraries. This software support is composed of specific libraries and a code generator used at design-time (see Figure 4.1). These libraries allow developers and security analysts to mark sensitive data in their code using annotations. Then, during code-generation, the toolchain produces a code where control-flow information is protected as well as sensitive data annotated during the design-time. As a result, software support allows the developer to easily generate a secure code that fits the security features provided by the hardware secure environment with minimal effort.

A trusted environment

The secure environment aims at ensuring sensitive data integrity at execution-time. To guarantee sensitive data integrity, one idea is to store them in a safe, trusted, and physically isolated memory in hardware. Such a trusted memory would isolate sensitive data making them unattainable from the untrusted memory corruptable by adversaries. However, while this principle protects sensitive data from any corruption, it cannot detect a memory exploit attempt. The process of detecting an attack remains as important as the protection of sensitive data for a critical system. Indeed, the detection of an attack and its report makes it possible to be aware of threats and anticipate security updates in real-time.

Furthermore, as a complement, detecting an attack helps developers of embedded system software to be aware of its failures. To perform both detection and data-flow integrity, the TrustFlow environment uses a trusted memory displayed in Figure 4.2 that handles a copy of sensitive data at run-time. While this principle can be compared to a voter for sensitive data, it allows tracing the data-flow integrity, detecting a memory violation, logging the anomaly, and finally, healing the corrupted data with a healthy one leaving the system in a safe state. Another argument in favor of duplication and detection rather than just dividing the memory spaces into two parts (one for sensitive data, one for insensitive data) is security tests. Embedded applications have far fewer software execution-time evaluation tools support than custom desktop applications [START_REF] Nethercote | Valgrind: a framework for heavyweight dynamic binary instrumentation[END_REF]. Memory safety issues are much more silent in embedded systems and more difficult to track [START_REF] Muench | What You Corrupt Is Not What You Crash : Challenges in Fuzzing Embedded Devices[END_REF]. By splitting the memory space, this issue may not be improved. Although the security level may be the same, the detection of silent memory corruption may be much harder.

To manage interaction with its trusted memory, TrustFlow provides both a custom load and a custom store operation. The custom store operation of sensitive data is similar to the store of non-sensitive data. The only difference is that the value of the sensitive data is duplicated in the trusted memory displayed in Figure 4.2. Of course, when sensitive data is updated using a custom store operation in the current memory the same operation is performed in the trusted memory. The custom load operation provided by TrustFlow works as similarly as the regular load of non-sensitive data. When used, the custom load fetches both sensitive data from the current memory and sensitive data from the trusted memory. Then, it verifies its integrity.

In the case of data-flow violation, the violated data in the regular memory differs from • ISA extension: The basic instruction set of the target load and store processor must be extended to support the two new custom instructions;

• The trusted memory: The trusted memory should be integrated within an existing load and store processor architecture. The latter interacts with the main core;

-Trusted memory size: Obviously, the size of the trusted memory restricts the number of sensitive data that can be protected at the same time. Also, the trusted memory needs to be aware of the liveliness of the stored sensitive data.

Freed data may take up valuable space in the trusted memory;

-Real-time constraints: The interactions with the trusted memory and the integrity checks should be fast;

• Main core logic: The target processor should perform sensitive data verification without inducing unwanted execution-time overhead. The processor should heal corrupted data on the fly without inducing any hazards.

A secure toolchain

The previously presented secure environment requires high-level software support to protect sensitive data. The environment only secures data that uses custom instructions. This means correct instructions should be used only and always to manipulate sensitive data.

If this property is guaranteed, the assembly code may ensure instruction-level separation between sensitive data and non-sensitive data controllable by adversaries.

Chapter 4. TrustFlow

In the scope of this work, TrustFlow considers that every in-memory code-pointer can be corrupted by an adversary. This includes backward-edge control-flow information such as stack return address and indirect forward-edges such as function pointer. To remind, function pointers are rarely used in embedded system programming and discouraged by [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF] but are still included in the threat model.

Obviously, after code generation, it would be impractical to have developers manually instrument the sensitive data-flow with custom instruction. Thus, for practicality and accuracy, the TrustFlow toolchain automates the instruction selection. It generates an assembly code where each sensitive data access is performed with the custom instructions.

To provide a degree of freedom, the toolchain provides several security levels. Such levels aim at protecting either backward-edges, backward-edges and forward-edges, forwardedges, or everything including spilled registers. Besides, these security levels provided by the toolchain can be used to perform security tests at different granularities. Finally, the TrustFlow toolchain provides a secure library with inline assembly routines that allow developers to manipulate custom sensitive data that are not considered by the threat model.

Unfortunately, the trusted memory size is limited. The amount of the trusted memory used by an application is directly proportional to the amount of sensitive data. Therefore, an excess of sensitive data in an application can lead to an overflow of the trusted memory.

To anticipate this issue, the TrustFlow toolchain suite proposes a trusted memory static First, a secure library is included in the development phase. This library allows developers and the security expert team to mark custom sensitive data. Then, the code passes the code generator provided by the TrustFlow security experts. After this step, sensitive 4.2. Approach code-pointers are protected. At this stage, the application is ready to be deployed, but, the latter can also be passed through the static analyzer to be verified.

A toolchain that respects the traditional software development flow can only be implemented with the help of a compiler framework infrastructure. However, as for the secure environment, it raises several challenges listed below:

• ISA extension: The targeted compiler should support the custom load and store instructions introduced by the hardware environment.

• Data selection: The targeted compiler should automatically select the correct load and store instruction to achieve instruction-level separation. It should also provide multiple security levels.

• Manual sensitive data annotation: The toolchain suite must provide a library that enables developers to annotate custom sensitive data at the source code level.

Then, the targeted compiler should interpret these annotations and make sure that these data are always accessed using custom instructions.

• Static analyzer: Given a binary, the static analyzer should be able to compute the trusted memory footprint of an application as accurately as possible.

Implementation

The TrustFlow framework is implemented within the RISC-V [START_REF] Waterman | The risc-v instruction set manual; volume ii: Privileged architecture, sifive inc. and cs division, eecs department[END_REF] instruction set architecture and the Clang/LLVM compiler infrastructure [START_REF] Lattner | LLVM: A compilation framework for lifelong program analysis & transformation[END_REF]. More precisely, the secure hardware environment extends the RISC-V Rocket-Chip generator in Chisel [START_REF] Asanovic | The rocket chip generator[END_REF]. The

Environment Implementation

At the hardware level, TrustFlow integrates two major components: a trusted translation lookaside buffer (TLB), and an extended processor pipeline with two custom instructions.

The TLB handles sensitive data and is used as a fast lookup memory. On the other hand, the processor pipeline is directly connected to the TLB to quickly store and retrieve sensitive data. The whole design is a 5-stage, in-order, 32bit RISC-V processor with a 16 kB data cache and a 4kB instruction cache. TrustFlow extends the RV32I basic instruction set with two new secure instructions given below:

• sws rs, imm(rd): stores a 32-bit word and duplicates the sensitive data in the trusted memory (secure store instruction)

• lws rd, imm(rs): loads a 32-bit word and checks the integrity of the data using the trusted memory (secure load instruction).

The two new instructions introduced by the TrustFlow extension inherit the properties of the classic RISC-V load ("lw") and store ("sw") instructions.

Translation Lookaside Buffer Design

Given the real-time requirements of life-critical embedded systems, TrustFlow's trusted memory is a fast Translation Lookaside Buffer (TLB) implemented as content-addressable memory (CAM) [START_REF] Pagiamtzis | Content-Addressable Memory ( CAM ) Circuits and Architectures : A Tutorial and Survey[END_REF]. This TLB can perform lookups in a single clock cycle. With a custom load (see Figure 4.4), the TLB uses the sensitive data address as a key to retrieve the matching data value. Then, both data from the regular memory and data from the TLB are compared by the checker. In case of mismatch, TrustFlow replaces the corrupted data with its healthy copy coming from the trusted memory and raises a "DFI" exception.

Each entry in the TLB is indexed by a vector V. The IDX value always points to free entry (0) of the TLB. If IDX does not point on a valid entry in the TLB, the latter is full, raising an overflow exception.

One can see that freed data may occupy precious space in the trusted TLB. According to the assumptions in section 1.1.3, the only freed data in the TLB are part of the freed stack frame. In other words, all data located below the stack pointer. Thus, when the stack pointer (sp) increases, all data that belong under it are considered as freed. To erase freed data, the trusted TLB acts as a garbage collector. Every time the stack pointer frees memory, all entries in the TLB that belongs to the freed stack slot are erased. By defining V as a vector stored in the trusted TLB, the latter follows the simple Algorithm 1 to eliminate freed data.

Algorithm 1: Hardware Garbage Collector foreach V ∈ T LB do if V (0) ∈ [Stack base ; Stack bound ] then if V (0) < SP V alue then V valid = 0 end end end

Processor Pipeline changes

To remind, the trusted memory is driven by two custom instructions. When used, these custom instructions pass the 5 stages of the processor pipeline as regular instructions.

Before digging into architectural details, here is a brief outline of the 5 stages of the RISC-V processor pipeline displayed in Figure 4.5:

• Instruction Fetch: The program counter register (PC) points on the instruction to fetch from the instruction memory and put it in the instruction register.

• Instruction Decode: The previously fetched instruction is then decoded into control signals. The operands of the instruction are moved to immediate fields or general-purpose registers.

• Instruction Execute: The instruction is executed. Usually, at this stage, either an arithmetic register/register operation or register/immediate operation is performed by the arithmetic-logic unit.

• Memory Access: If the instruction is a load or a store, the memory is accessed at this stage. Otherwise, the instruction is simply forwarded to the next stage.

Usually, for a load or store instruction, the accessed memory address comes from the arithmetic-logic unit and the data to store from "rs2".

• Write Back: The results of an operation performed by an instruction are written to a destination register within the register file.

The custom load and store instructions trigger the TrustFlow extension during the memory access stage. At this stage, TrustFlow processes sensitive data address pairs needed to be stored/checked in/from the trusted TLB.

TrustFlow is aware of the validity of the instruction flow in the pipeline and replicates the regular memory access to the trusted TLB. For instance, each invalid custom "load" with the normal memory due to a pipeline stall (cache miss) is also canceled with the TLB inhibiting the checker. Likewise, a canceled "custom" store instruction is never committed to the trusted TLB. TrustFlow performs the data integrity checks during the write back stage of the pipeline. The checker is triggered by a custom load and verifies that data fetched from the data cache do not differ from the trusted TLB. In the case of discrepancy, a data-flow violation is logged and the faulty data is replaced on-the-fly by the checker.

A stage by stage simplified pipeline outline of TrustFlow is given below, the blue components in Figure 4.5 represent the important TrustFlow modules.

Healing data on the fly by replacing corrupted one is an important feature of TrustFlow.

Another solution would be to revert the execution flow to a previous state and re-execute and entire section. However, it would allow an attacker to replay his attack. Also, memory exploits can be seen as a non-deterministic disturbance. They are unpredictable and therefore not appreciated by critical deterministic systems. As a result, reverting the execution flow due to a non-deterministic attack may be inconsistent with deterministic

Toolchain implementation

To ensure instruction-level separation, the TrustFlow toolchain extends the Clang/L-LVM [START_REF] Lattner | LLVM: A compilation framework for lifelong program analysis & transformation[END_REF] compiler with additional passes. With strong compiler support, the toolchain simplifies the integration and accuracy of security. Also, the second goal of the toolchain is to deliver verification options regarding the amount of trusted memory consumed by an application.

Required compiler changes

The custom instructions introduced in the RISC-V ISA resulted in an extension of the RISC-V LLVM backend.

As pointed out earlier, the goal of the compiler is to protect both indirect backward and forward-edges preventing memory exploits. By design, the compiler spills the return address (backward-edge control-flow information), and some registers of a calling function in the prologue of the called function. Also, when a called function returns to its caller, the return address and the spilled registers are restored during the epilogue. By targeting the calling convention and more precisely the in-memory return address stack an attacker can divert an indirect backward-edge. To address this issue using the TrustFlow environment, both the prologue and the epilogue should use custom instructions when spilling/restoring the caller register and the return address in a stack frame.

By leveraging an in-memory bug an attacker may also target indirect forward-edges such as function pointers. To protect indirect forward-edges, function pointers should be manipulated with custom instructions. However, protecting every in-memory function Chapter 4. TrustFlow pointer is less trivial as for the backward-edges. Indeed, the data-flow of function pointers must be analyzed to determine when and where they are spilled and restored in/from the memory. Each time it happens, it must be achieved with a custom instruction. To perform such protection, the compiler must analyze and determine each function pointers' flow.

Then, during instruction selection, each load/store involving a function pointer should use a custom instruction. Finally, to determine the trusted TLB footprint of an application, the compiler integrates a static analyzer that crosses the application code and determines the worst-case trusted TLB usage.

Introduced passes workflow

Multiple passes are introduced in the LLVM compilation pipeline to achieve fine-grained data-flow integrity. Figure 1.6 displays a simplified representation of the LLVM backend pipeline with the TrustFlow introduced passes.

IR Instruction Selection

Instruction Scheduling

Machine Inst Optimization

Register Allocation PEI Insertion Final Optimization 4.3. Implementation pass during prologue-epilogue insertion. To protect backward-edges, the prologue/epilogue insertion pass is modified to spill/restore function return address with custom instructions. Also, at this stage, the improved compiler offers an option to secure every spilled register with custom instructions. For more details about the prologue-epilogue insertion, we refer the reader to Annex B.

Static analyzer

After secure code generation, developers have no idea about the cost of their program in the trusted TLB. They can perform tests on the hardware to determine whether the trusted memory overflows or not. This approach is unpractical and time-consuming. To safely use the TLB, developers require a practical tool that ensures that their application fits the TLB according to the security level.

To do so, the TrustFlow comes with a static verification compiler extension that estimates the worst-case maximum amount of trusted memory used by an application. This pass is implemented as a "Machine Module" pass within the RISC-V LLVM backend. Also, the pass is only compatible with full Link-Time Optimization (full-LTO). During compilation, the full-LTO optimization merges separated modules into a single monolithic Intermediate Representation module. This monolithic module is then passed to the LLVM backend allowing the static analyzer pass to see the program as a whole and perform interprocedural analysis. The static analyzer pass traverses each function evaluating its trusted memory costs. Then, the static analyzer pass reconstructs the entire program control-flow graph. This operation results in the construction of a weighted directed graph. More precisely, as we forbid recursion in our approach [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF], this constructed directed graph is acyclic (DAG).

Unfortunately, static control-flow graphs are often imprecise due to indirect forwardedges targets. To generate a fine-grained control-flow graph the static analyzer requires Chapter 4. TrustFlow little human interaction. To do so, the Clang front end of the compiler is improved and provides a high-level annotation that can be used by developers to mark functions that handle indirect control-flow transfers with the name of their potential target(s). With this support, the compiler can construct a fine-grained weighted directed acyclic graph.

To determine the maximum usage of trusted TLB by an application, the static analyzer determines the deepest path in the constructed weighted DAG. As verification, the static analyzer makes sure that the generated call graph does not contain any cycles. For space reasons, we do not detail the cycle detection algorithm performed by the static analyzer.

However, the cycle detection is based on a depth-first search algorithm that colors visited vertices.

The deepest path problem for a weighted directed acyclic graph is known to be a linear problem. To solve it, the static analyzer uses a classical topological sorting algorithm on the DAG to sort all the vertices. This algorithm performs a linear ordering of all vertices such that for every direct edge between two vertices A and B, vertex A comes before vertex B in the ordering.

Once the vertices are sorted in a stack S, the static analyzer initializes the distance of every vertex as negative infinity (NINF) and the distance of the root vertex (application entry point) as 0. Then, the vertices are processed one by one by popping the stack. For every vertex being processed, the static analyzer updates the distances of its child(s) using the distance of the one being processed. The entire algorithm is summarized in Algorithm 2 snippet.

Algorithm 2: Deepest Path Algorithm

foreach vertex ∈ DAG do dist[vertex] = N IN F end dist[root] = 0 ; while S = ∅ do vertex = S.pop(); if dist[vertex] = N IN F then foreach child ∈ vertex do if dist[child] < dist[vertex] + child.getW eight() then dist[child] = dist[vertex] + child.getW eight(); end end end end deepth = 0; foreach d ∈ dist do if d > deepth then deepth = d; end end Time Complexity O(V+E)
As a result, the deepest path corresponding to the worst-case trusted memory usage

Evaluation

This section assesses the TrustFlow framework. The toolchain requires about 1500 lines of C++ code to be added to the Clang/LLVM compiler infrastructure. Also, the TrustFlow environment is synthesized on a Xilinx ARTY-35T FPGA and requires 400 lines of Chisel code to be added in the RISC-V RocketChip generator. To validate the security of the concept, TrustFlow is confronted with the RIPE benchmark suite [START_REF] Wilander | RIPE: runtime intrusion prevention evaluator[END_REF]. Then, we evaluate the costs of the TrustFlow environment in hardware. This includes a trusted memory size benchmark regarding different life-critical medical applications, execution-time overhead induced by the TrustFlow extension, and the additional LUTs and Flip-Flops required by TrustFlow. Finally, the main goal of this section is to demonstrate that an acceptable level of security can be achieved on a wide range of programs with a very small trusted TLB and at the lowest costs.

Security evaluation

The RIPE benchmark suite [START_REF] Wilander | RIPE: runtime intrusion prevention evaluator[END_REF] provides different attack patterns to test the coverage of countermeasures against memory attacks. These attacks use five different dimensions: the location, the target code pointer, the overflow technique, the attack code, and the function abused. Following the assumptions [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF], this evaluation considers out of scope all attacks involving the dynamic memory allocation from the benchmark suite. Also, as Trust-Flow detects sensitive data corruption at execution-time, the evaluation is focused on the targeted code pointers regarding its location and the overflow technique. In the evaluation, the benchmark is compiled with 3 different options: backward-edge protection (B), backward-edge and spilled registers (BS) protection and finally, backward-edges spilled registers, and forward-edges (BFS) protection. The results are summarized in Table 4.1.

D X X O.S X X O.S X X X X BS D D X O.S X D O.S D X D X BFS D D D O.S X D O.S D X D X
X=undetected, D=Detected and healed by TrustFlow, O.S=Out of the scope of the TrusFlow-X framework.

After compilation with full protection and execution on the environment, TrustFlow 4.4. Evaluation protects and detects any attack from the benchmark suite that targets: function return addresses, stack function pointers (both in the stack or pass as a parameter), data section function pointers and BSS function pointers. Besides, the TrustFlow framework is also able to protect and detect any attacks that target function pointers residing close to a buffer within a structure located either in the stack, the BSS, or the data section. However, these function pointers should only be used with one level of dereferencement. Of course, following the threat model in section 4.2, none of the attacks corrupting a target code pointer in dynamic memory is detected. From Table 4.1 it also appears that the security difference between "B" and "BS" is less. Only two additional direct attacks and indirect attacks are detected by the "BS" option.

Several data-oriented attacks are also implemented in the benchmark suite. At this moment, the improved compiler is not able to automatically protect security-critical data such as numerical values used for a branch condition, or token used for privileges. However, the TrustFlow environment provides the necessary support to ensure its integrity. Finally, any data leakage that does not corrupt sensitive data is not detected by TrustFlow.

Environment evaluation

Trusted memory benchmark

While TrustFlow is capable of ensuring fine-grained CFI through fine-grained DFI, its security level is ensured by the trusted memory that has a fixed size. To prove that TrustFlow can handle a wide range of life-critical applications respecting our software assumptions [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF] (see section 2.2) with a reasonable fixed TLB size, this section assesses the amount of trusted memory consumed by various medical applications that follow our software assumptions:

1. Inverse Radon Transform from the HERMIT benchmark suite [START_REF] Limaye | HERMIT : A Benchmark Suite for the Internet of Medical Things[END_REF]. This application is commonly used in portable ultrasound and MRI devices. It allows reconstructing the output image from a 159KB 2D sinogram input data file for visualizing abnormal openings in the body.

2. SecPump [START_REF] Bresch | SecPump: A Connected Open Source Infusion Pump for Security Research Purposes[END_REF] a fully open-source wireless insulin pump. The SecPump project aims at serving as a medical platform for security evaluation.

3. The open-source syringe pump project [START_REF] Wijnen | Open-Source Syringe Pump Library[END_REF]. Open-syringe proposes an inexpensive Arduino based medical for research purposes. This project is easily portable on RISC-V and highly representative of a real medical device.

4. ARM Mbed TLS library [START_REF] Arm | Mbed TLS[END_REF]. While not entirely dedicated to medical devices ARM Mbed TLS is a cryptographic library reference for embedded systems.

The applications are benchmarked using the static analyzer. The results outputted by the static analyzer represent the worst-case trusted TLB usage according to a path taken within an application. The static analyzer does not guarantee the coverage of the longest Chapter 4. TrustFlow path and if it is frequently taken. The trusted memory benchmark is achieved with the following assumptions:

• The applications are compiled and evaluated without recompiling external libraries;

• Five data-flow integrity levels are applied; backward-edges ("ret"), forward-edges ("pointer"), backward-edges and spill registers ("spill"), backward-edges and forwardedges ("ret+pointer"), and finally, forward-edges and backward-edges with spilled registers ("spill+pointer");

• The compilation options recommended for the evaluated applications are kept as provided in their dedicated Makefile, we only changed the compiler optimization level to measure the impact on the trusted memory. Three compiler options are considered: "O0, O2, Os"

The results of the benchmark are displayed in Figure 4.8. The Y-axis is the maximum entries required in the TLB. The X-axis is the compiler optimization.

Pointer Ret

According to the results, only a reasonable amount of trusted memory is used by all evaluated critical applications. The "Inverse Radon Transform" application consumes the most number of entries in the trusted TLB. More precisely, 50 entries with full protection for an application totaling about 7000 lines of code. However, 50 entries of 64 bits (8 bytes) only represent 400 bytes of a trusted memory, which is less than a kB. Securing spilled registers highly increases the consumption of trusted memory. For each function call, every register spilled in memory is saved by the compiler using a custom instruction.

Evaluation

Besides, a better compiler optimization option increases the number of spilled registers and, consequently, the consumed trusted memory. Indeed, the compiler tends to favor the use of registers per function instead of memory accesses to improve the execution speed.

Comparing with the previous security evaluation, the cost of protecting spilled registers is very high for a security level very little different from the backward-edge protection.

Depending on the threat model and system constraints, securing the spilled registers may not be worth the costs. Conversely, according to the previous security evaluation, protecting function pointers (forward-edges) render a wide range of attacks ineffective.

According to the measurements, the effect of function pointer protection is ineffective on the trusted memory. Function pointers are rarely used in critical embedded systems [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF] (even never used, see Figure 4.8, RadonAna, and Open-Syringe).

The results outputted by the static analyzer represent the worst-case trusted TLB usage according to a path taken within an application. To remind, the static analyzer does not guarantee the coverage of the longest path. To verify the accuracy of the static analyzer and to validate its measurements the static measurement of RadonAna is compared with a dynamic analysis using 6 various compiler optimization options. We selected RadonAna because it totals around 7000 lines of codes, 130 vertices, a large corpus of input that covers many different paths in the application, and because the application seems to consume the most memory.

An interesting point, more related to section 4.4.1 is that TrustFlow's static analyzer detected several vulnerabilities in the HERMIT benchmark suite. Some of these vulnerabilities included infinite call sequences causing deadlocks in the benchmarked application.

The results of the static analysis versus the dynamic analysis are displayed in Fig- The dynamic evaluation comparison in Figure 4.9 confirms the trustworthiness of the static analyzer. It also confirms that in real execution the worst-case evaluation given by the static analyzer is not always attained. Finally, the dynamic benchmark reinforces the static benchmark and confirms the hypothesis that a small trusted memory with a hardware garbage collector can secure reasonable embedded applications. The Y-axis is the maximum entries required in the TLB. The X-axis is the compiler optimization.

Execution time overhead

Since TrustFlow is dedicated to bare-metal/RTOS embedded systems, it is not relevant to port the well-known benchmark suite SPEC2006 CPU [START_REF] Henning | Spec cpu2006 benchmark descriptions[END_REF]. Moreover, TrustFlow cannot support the Linux Kernel. So this assessment turned to the CoreMark benchmark suite [START_REF] Gal-On | Exploring CoreMark™ -A Benchmark Maximizing Simplicity and Efficacy[END_REF]. CoreMark contains 4 algorithms such as list processing (find and sort), matrix manipulation (common matrix operations), state machine, and CRC (cyclic redundancy check) that are designed to run on devices ranging from 8-bit microcontrollers up to 64-bit microprocessors. Thus, CoreMark is easily portable on bare-metal architectures such as TrustFlow.

To measure the execution-time overhead induced by the TrustFlow environment, the processor is synthesized on a Xilinx ARTY-35T FPGA with a fixed TLB size of 384 bytes. The CoreMark benchmark suite is compiled using the TrustFlow's Clang/LLVM extended compiler using optimization level 3 with 5000 iterations. The measurements revealed a processor execution ticks overhead of 0.0087% for the backward-edge protection and 0.021% for the spill protection. As a result, the execution-time overhead induced by TrustFlow is negligible. This can be easily explained by the fact that all operations performed by TrustFlow in hardware are carried out in parallel to the main pipeline. Thus, any custom instruction triggers an independent hardware extension that only performs a simple check operation at the write-back stage.

Also, it should be mentioned that TrustFlow does not induce any size overhead on the final binary of the benchmark. Custom load and store instruction just replace the classic load and store instruction for sensitive data.

Evaluation

Hardware costs

The TrustFlow hardware extension overhead can be divided into two distinct parts: (1) a trusted external fast memory with a garbage collector and (2) additional instructions with an in-pipeline checker. Like any hardware implementation, the TrustFlow core consumes additional LUTs and Flip-Flops.

The additional hardware cost due to the two new instructions is very low compared to the hardware cost induced by the trusted memory. The reference RISC-V RocketChip processor [START_REF] Asanovic | The rocket chip generator[END_REF] consumes a total of 16671 LUTs and 9905 Flip-Flops. The addition of two new instructions in the core, the checker, and the digital logic that ensures memory management increases the number of LUTs (16789) by 1.03% and the number of Flip-Flops (10020) by 1.16%. However, when adding a fixed trusted memory of 384 bytes (48 entries), the design consumes a total of 18643 LUTs (11% increase) and 12099 Flip-Flops (22% increase).

In terms of performance, the two instructions are similar to the load and store instruction. Both custom instructions manage the trusted memory in parallel with the main memory. Similar performances are measured between the custom load and store instruction and the regular ones. The core modifications induced by the addition of these instructions have mostly no effect on the timing performance of the core. TrustFlow is able to broadly reach the same running frequency on the embedding core. However, a negligible timing delay may impact the system performances in case of data discrepancy due to the checker and the data correction.

Discussion

It is fair to affirm that TrustFlow is first designed to secure critical bare-metal applications. In theory, TrustFlow can boot a lightweight real-time operating system such as FreeRTOS. Indeed, the TrustFlow's trusted memory is a table, mapping address and sensitive data pairs that are compliant with multi-threading. Unfortunately, a simple small trusted memory such as the one exposed in this Chapter is not enough to store all the critical data of the tasks shared by an application on a single processor. Besides, the current hardware implementation of the TrustFlow memory garbage collector does not support multiple stacks. The garbage collector invalidates part of the trusted memory data depending on the value of the stack pointer. Unfortunately, with a multi-tasks application, the real-time operating system maintains several stacks inducing stack pointer changes at each context switch. Thus, the current hardware garbage collector that follows algorithm 1 may evict valid sensitive data in the trusted memory if the stack of the new active task is at a higher address than the stack of the suspended task.

To address multitasking, one solution would be to map trusted memory registers.

These registers may allow a real-time system to configure the garbage collector with the address ranges corresponding to the different stacks in memory. The global idea would be to make the garbage collector aware of the different stacks. However, this improvement may introduce new limitations. Indeed, the number of trusted memory registers will limit the number of tasks protected by trusted memory. Although the concept lends itself to it, it would induce high hardware costs to keep the same performances as TrustFlow while protecting all the sensitive data per process.

Another way to handle multiple tasks would be to save and restore the trusted memory per process. Taking the FreeRTOS [START_REF] Barry | Freertos[END_REF] real-time operating system as an example, the task control block (TCB) structure can be extended such that it handles valid stack entries from the trusted TLB. Then, during a context switch, the scheduler of the operating system can, therefore, save the state of the task trusted memory in the extended TCB, and restores the following running task trusted memory. Of course, this concept should be coupled with software isolation (SFI) such that the TCB of suspended tasks cannot be corrupted by a memory violation in a running task.

Finally, the TrustFlow hardware trusted memory is size limited. This work provides an accurate static analyzer such that developers can easily optimize their application to fit the trusted memory. During the evaluation of the concept, and like other work related to shadow stacks [START_REF] Christoulakis | HCFI : Hardware-enforced Control-Flow Integrity[END_REF][START_REF] Davi | Hafix: Hardware-assisted flow integrity extension[END_REF][START_REF] De | FIXER: Flow Integrity Extensions for Embedded RISC-V[END_REF] we did not face any overflow issue with a fixed trusted memory. However, considering manufacturing TrustFlow for critical systems at a large scale, giving trusted memory depth metrics is not enough. Indeed, the overflow issues related to the trusted memory must be supported. One way to deal with it would be to raise an interruption when the trusted TLB is full and to transfer the highest stack data to the current memory or an extended TCB for a real-time system. However, once again this mechanism should be coupled with SFI to protect the transferred data.

At the software level, TrustFlow ensures control-flow integrity through sensitive data-4.5. Discussion flow integrity using compilation. Unfortunately, any third-party libraries that are not compiled with the TrustFlow Clang/LLVM extension are unprotected. Thus, these thirdparty libraries constitute new attack surfaces not covered by the protection. To deal with this case, the TrustFlow framework can be associated with a patching application. The latter could easily disassemble third-party libraries, identify the load and store instructions that manipulate sensitive data and patches them using custom instruction. However, this process is less precise than a regulation compilation workflow. It could introduce hazards in the assembler. Pre-compiled application codes are not trivial to analyze. Some of them are obfuscated, making static analysis very difficult, requiring error-prone human interaction.

Regarding function pointers protection, the current Clang/LLVM extension handles one level of dereferencing. Thus, in the case of function pointers that are dereferenced across multiple structures, the compiler is not able to generate the correct instructions.

Although this goes against the assumptions made in section 1.1.3, and the safety-critical code practices proposed by [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF][START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF], this issue requires manual code instrumentation by the developer at the assembler level.

Finally, at present, the TrustFlow compiler extension cannot protect the induction variables. These variables are usually increased or decreased within loops and are the targets of Data-Oriented Programming attacks [START_REF] Hu | Data-Oriented Programming : On the Expressiveness of Non-Control Data Attacks[END_REF]. We are currently working on a pass similar to the function pointer identification pass to protect such variables.

Comparison with related work

In comparison with other memory safety protection work, TrustFlow is an enhanced instruction driven shadow stack [START_REF] Bresch | TrustFlow : A Trusted Memory Support for Data Flow Integrity[END_REF] that can ensure fine-grained CFI protecting sensitive data-flow. In this section, we discuss a coherent selection of well-known hardware-software co-design CFI protections and their limitations with TrustFlow.

HCFI [START_REF] Christoulakis | HCFI : Hardware-enforced Control-Flow Integrity[END_REF] is an extension of SPARC architecture that enforces CFI. HCFI enforces finegrained backward-edge CFI thanks to a hardware shadow stack that stores the call stack.

As TrustFlow, this policy provides an accurate security level but can only guard a limited call depth. Concerning forward-edge CFI, HCFI enforces a policy label thanks to two additional instructions. Although restricted, HCFI's indirect forward-edges can still target multiple locations making the overall protection a little coarse-grained. In comparison,

TrustFlow enforces fine-grained forward-edge integrity. Both HCFI and TrustFlow are limited by the size of the trusted memory. However, HCFI consumes twice less memory per sensitive data than TrustFlow because it does not store the address of sensitive data as a key in its trusted memory. Besides, HCFI provides specific support for recursion.

TrustFlow supports recursion but prohibits it through its assumptions. Finally, both solutions induce less than 1% execution-time overhead.

At the software level, the HCFI protection is ensured with binary instrumentation scripts. While this process is scalable for small applications, it is difficult to deploy in a production environment. The code generation is heavy and requires several steps each time a binary had to be generated. Conversely, TrustFlow provides an easy to use, accurate compiler support.

HAFIX [START_REF] Davi | Hafix: Hardware-assisted flow integrity extension[END_REF] is a hardware backward-edge CFI based on labels and an isolated memory.

Each time a function is called, a custom instruction is executed by the processor. This is accompanied by a compiler extension that generates a secure code using the additional instructions. Thus, the security implementation is straightforward to use for non-security experts which is consistent with the philosophy of TrustFlow.

FIXER [START_REF] De | FIXER: Flow Integrity Extensions for Embedded RISC-V[END_REF] proposes a decoupled and flexible RISC-V compatible coprocessor to enforce both forward-edge and backward-edge control-flow integrity. FIXER targets hybrid 4.6. Comparison with related work processors based on an unmodified RISC-V core interfaced with a reconfigurable FPGA core. The FPGA part of FIXER implements a shadow call stack for fine-grained backwardedge and a policy matrix to enforce forward-edge protection. More precisely the FPGA is interfaced with the RoCC interface of the RISC-V processor and interacts with it using the dedicated accelerator instructions. FIXER proposes developers to annotate each function call and returns with tags at the source code level to protect their application. These tags are then translated into instructions that interact with FIXER thanks to a binary instrumentation script that parses assembly files generated by the GCC compiler. While this technique is automatic, we argue that manually annotating an application's source code for security is not very practical. This argument is also supported by [START_REF] Szekeres | Sok: Eternal war in memory[END_REF]. In contrast, TrustFlow automates the instruction selection at compilation time freeing the user from any binding source code annotation. Also, unlike TrustFlow, the FIXER forward-edge policy matrix is coarse-grained. Indeed, indirect forward-edges can still target valid destination sites that are invalid for a specific call. In closing, both FIXER and TrustFlow have a negligible execution-time overhead. However, the flexibility proposed by FIXER is a great asset over TrustFlow. Indeed, the trusted memory size (shadow call stack) of FIXER can be optimized on purpose and accommodate new security threats.

Finally, TrustFlow can be compared with well-known fine-grained tagged memory policies such as HDFI [START_REF] Song | HDFI : Hardware-Assisted Data-flow Isolation[END_REF] and LowRISC [START_REF] Song | Towards general purpose tagged memory[END_REF]. They use two tag levels (IL1 and IL0) to separate sensitive data (IL1) from regular data (IL0). To trace the data-flow, HDFI [START_REF] Song | HDFI : Hardware-Assisted Data-flow Isolation[END_REF] extends the RISC-V processor memory with an additional one-bit tag field for every word.

To enforce sensitive data isolation, HDFI introduces custom store and custom load instructions as TrustFlow. These instructions are supported by a modified processor logic such that; every regular write instruction defines a data and set the tag field to zero, every special write instruction defines a sensitive data and set the tag field bit to one and every special load instruction checks that the used sensitive data has a tag set to one. Thus, a regular write that modifies sensitive data also changes its tag. When this sensitive data is re-used by a custom load instruction, the processor detects a wrong tag and raises an exception. HDFI has a major advantage over TrustFlow in terms of memory limitation.

Indeed, HDFI protection is not restricted by the size of the trusted memory. However, it induces one bit overhead per double memory words which also is not negligible.

The HDFI approach carries full operating system support which TrustFlow does not.

However, in terms of safety, HDFI does not provide any recovery mechanism capable of restoring corrupted data. While a custom exception handler can be implemented to re-execute the faulty code section, it would allow an attacker to replay his attack until blocking a system. Also, it may induce a non-determinism source of perturbation over the critical device. Finally, HDFI, LowRISC, and TrustFlow have full toolchain support that facilitates the integration of security into systems.

Chapter 4. TrustFlow

Conclusion

This Chapter proposes an innovative practical defense against memory-based exploits on life-critical medical devices. According to the state-of-the-art, it seems that existing works are not the most appropriated for medical devices. Many solution overlooks finegrained security, safety, and other practical aspects that cause their solutions to be neglected by life-critical device manufacturers. Many concepts often offer incomplete defenses and a poor balance between execution-time overhead and accuracy. On top of that, most hardware-based countermeasures lack software support so that they can be used with minimal human efforts. As long as developers have to rewrite some parts of the software assembly code by hand, security may never be integrated. Besides, binary instrumentation is neither modular nor practical in a software production environment.

It sometimes breaks the C programming language structures and forces developers to perform security tests at the end of a system's development phase. Finally, among all existing memory safety protections, the state of a system after detecting an attack is never addressed. For critical devices, detecting an attack is only the first step, the second step is to move the system to a safe state that does not impact the users' safety. None of the current countermeasures exhibit innovative techniques to recover from memory attacks.

To address these gaps, TrustFlow, proposes a novel practical framework that simplifies the integration of memory safety in critical systems while keeping a sufficient tradeoff between security, safety, and performance. The contribution is composed of an LLVM based secure toolchain able to generate secure code for a RISC-V based secure environment that can prevent, detect, log, and self-heal critical devices from memory exploits.

The whole hardware environment is composed of an extended RISC-V processor communicating with an isolated trusted memory that handles duplicated sensitive data.

Motivation

With the emergence of the Internet of Things (IoT), there is an increasing trend of connecting tiny devices to the Internet. In healthcare, this trend has resulted in exponential growths of related security and safety incidences widely discussed along with this thesis [START_REF] Lily | Medical Devices Are the Next Security Nightmare[END_REF][START_REF] Newman | A New Pacemaker Hack Puts Malware Directly on the Device[END_REF]15,[START_REF]Hospira Multiple Products Buffer Overflow Vulnerability[END_REF][START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF].

Currently and for the coming years, the IoMT's market share is growing. This creates new business opportunities for manufacturers, start-ups, and independent innovators.

However, the increase of connected devices directly increases the potential attack surfaces and data theft. If the Internet of Medical Things manufacturers continues to follow the trend of ignoring security issues in favor of adding fashionable features to their products, security incidents are likely to occur shortly.

The previous Chapter of this thesis introduced TrustFlow, a security-oriented processor with software support that ensures fine-grained memory safety in life-critical systems.

To remind, TrustFlow is an architecture based countermeasure that protects the securitycritical dataflow. Unfortunately, TrustFlow relies on invasive hardware changes to operate.

Today's IoMT manufacturers or even startups do not necessarily have the financial capacities to produce silicone with specific support for memory safety. Also, sometimes, critical medical devices are developed on microcontrollers that do not allow architectural modifications [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF]. To push is further, IoMT devices are often developed on low-end microcontrollers that do not support hardware-based memory safety support [15,[START_REF]Hospira Multiple Products Buffer Overflow Vulnerability[END_REF][START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF]. Indeed, these low-end microcontrollers are often highly constrained. They do not benefit from the same security support as traditional desktop systems. For instance, less than 50% of embedded system application enforces the Data Execution Prevention (DEP) protection and less than 5% enforces both the Address Space Layout Randomization (ASLR) and the Stack Smash Protector (SSP) [START_REF] Abbasi | Challenges in designing exploit mitigations for deeply embedded systems[END_REF][START_REF] Wetzels | Ghost in the machine: Challenges in embedded binary security[END_REF]. Usually, IoMT devices run on the metal relying on exotic architectures such as ARM, AVR, MIPS, RISC-V. Each low-end microcontroller comes with fixed and specific hardware features that often have no common dedicated support for memory safety. Yet, despite these constraints, medical devices still need to be protected from security threats.

This Chapter, therefore, takes a different approach to the TrustFlow approach outlined in Chapter 4. More precisely, this Chapter follows the second approach exposed in Chapter 2, section 2.3. This time, the thesis assumes that critical applications are developed on off-the-shelf fixed microcontroller architectures. Thus, security countermeasures against memory exploits can only be implemented at the software level. However, the objectives of this Chapter remain the same as TrustFlow, and those set out in the thesis approach in Chapter 2:

• Security: Like TrustFlow, the primary goal of this software-only approach is to prevent and harden memory-exploits development.

• Performances: This thesis targets industrial IoMT applications. As manufacturers optimize their application to the maximum, the countermeasures should not induce 5.1. Motivation prohibitive execution-time overhead. To remind [START_REF] Szekeres | Sok: Eternal war in memory[END_REF], embedded system manufacturers may not accept more than 5% execution-time overhead.

• Space overhead: IoMT embedded applications are highly constrained. Embedded system platforms have little memory, of the order of a kilobyte. As manufacturers tend to reduce the cost and the space taken by an embedded application to its lowest, security protections should not induce prohibitive extra memory overhead.

• Flexibility: In comparison with TrustFlow, this time, the security must be the least intrusive. It should be easy to integrate within a practical embedded software development cycle, including incremental tests and targeting a wide range of embedded systems.

• Compatibility and modularity: The security should be compatible with thirdparty libraries and the existing C standards. Also, it should be compatible with incremental development and able software developers to work with separated modules.

• Practicality: To avoid security mistakes the security should be transparent for the developer. Embedded system developers do not always have advanced expertise in security. Thus, countermeasures should require minimum user interactions [START_REF] Szekeres | Sok: Eternal war in memory[END_REF].

To address these challenges, this chapter proposes BackGuard, a flexible compiler toolchain that mitigates memory exploits. BackGuard reduces memory-based attack surfaces by hardening embedded applications with a bitmap-based backward-edge controlflow integrity protection. Besides, BackGuard complements the bitmap with an adaptation of the SSP called Random-Guard, and memory barriers called RO-Guards. The Random-Guards cluster vulnerable buffers from sensitive data such as function pointers.

Conversely, RO-Guards clusters memory sections preventing spatial memory exploits to spread. Finally, BackGuard enforces DEP.

In this work, the efficiency of BackGuard is showcased on the ARM Cortex-M architecture. However, at the end of the chapter, several openings are given to allow BackGuard to be ported to other architectures at a lower cost. Finally, BackGuard induces the least possible modification of existing embedded systems development tools. In summary, the major contributions of this work are listed below:

• Backguard; a set of LLVM [START_REF] Lattner | LLVM: A compilation framework for lifelong program analysis & transformation[END_REF] compiler plugins that harden low-end microcontrollers against memory safety exploits. BackFlow is highly flexible, easy to use, deployable on several architectures requiring no internal changes of the LLVM compiler;

• A security evaluation of BackGuard; Both a quantitative and qualitative security evaluation of the framework are performed in this Chapter. This includes the average target reduction (AIR) measurements of the control flow integrity protection, the return-oriented programming gadgets reduction, and a qualitative basic exploitation test based on SecPump a security-critical wireless infusion pump [START_REF] Bresch | SecPump: A Connected Open Source Infusion Pump for Security Research Purposes[END_REF].

Chapter 5. BackGuard

• Benchmark of Backguard; The code-size overhead induced by BackGuard is measured on a real representative wireless infusion pump. Regarding the executiontime overhead, 145 measurements are performed on various benchmark programs such as Dhrystone [START_REF] Weicker | Dhrystone: A synthetic systems programming benchmark[END_REF], CoreMark [START_REF] Gal-On | Exploring CoreMark™ -A Benchmark Maximizing Simplicity and Efficacy[END_REF], and BEEBS [START_REF] Pallister | BEEBS: Open Benchmarks for Energy Measurements on Embedded Platforms[END_REF].

Approach

Approach

To address the BackGuard objectives, this chapter proposes the same top-down approach as TrustFlow. However, unlike the previous chapter on TrustFlow, the ability to integrate security features is much more restricted. While TrustFlow assumes that the security can be implemented on both the hardware and the software layer, BackGuard assumes that microcontrollers are provided as is by manufacturers and thus only the software layer can be modified. Like TrustFlow, Backguard tackles the memory safety issue from the initial software design-time to the execution on the hardware. At execution-time, the application is protected in a secure environment. This time, the secure environment is assured by both the software and the hardware. But, as the hardware is immutable, extra security features for memory safety can only be managed by the software. It should be mentioned that the software can efficiently use the available hardware to create a secure environment. The main purpose of the secure environment is to protect embedded software against spatial memory-safety exploits. This secure environment focuses on buffer overflow mitigation because they represent the top-rated threat [START_REF] Andreeva | Industrial control systems vulnerabilities statistics[END_REF] in the current low-end embedded system.

As TrustFlow, the secure environment assumes that the executed embedded application contains memory corruption bugs that can be turned into exploits. However, as BackGuard has no access to the hardware layer to provide extra security features, and to not induce The secure environment is entirely managed by the software. The latter configures the Chapter 5. BackGuard fixed hardware efficiently and offers run-time control-flow integrity protection generated at compilation-time by a flexible toolchain. This toolchain is composed of both secure libraries and a set of compiler plugin. These libraries are linked to the final application to ensure the proper hardware configuration while the compiler hardens the final binary code against memory exploits. Following the approach, the BackGuard's software toolchain allows the developer to easily generate a secure code with minimal effort as the security is enforced by the compiler.

Protection concept

Typical control-flow exploits leverage in-memory control-flow information to hijack the execution flow. This control-flow information is either indirect backward-edges (function return addresses) or indirect forward-edges (function pointers). BackGuard focuses on indirect backward-edge control-flow integrity. Regarding indirect forward-edges, several practical compiler works have already taken the issue seriously and provided flexible defenses [START_REF] Tice | Enforcing Forward-Edge Control-Flow Integrity in GCC & LLVM[END_REF]. Also, indirect forward-edges such as C++ virtual methods tables pointers are less frequent in embedded system programming, and specifically in safety-critical embedded applications.

Protecting indirect backward-edges implies the protection of return addresses. To do so, one way is to duplicate the function return address into a shadow stack [START_REF] Bresch | A red team blue team approach towards a secure processor design with hardware shadow stack[END_REF][START_REF] Bresch | Stack Redundancy to Thwart Return Oriented Programming in Embedded Systems[END_REF].

Then, when a function returns, the validity of the return address is checked using the shadow stack. Another concept is to identify return addresses on an isolated bitmap. The bitmap is an array that identifies a valid return address destination using a single activated bit. Thus, at runtime, before each function return, the bitmap is checked to certify that the destination address is valid. BackGuard proposes bitmap-based control-flow integrity lighter than Microsoft Control Flow Guard that does not require a complex operating system. Indeed, BackGuard mostly targets single stack embedded system applications. It proposes more precise bitmap protection than [START_REF][END_REF] thanks to return address activation and deactivation in the bitmap.

The overall bitmap protection concept proposed by BackGuard is displayed in Figure 5.3. in the activation of a corresponding bit in the bitmap. Then, when a function returns, its return address is translated to check whether the corresponding bit in the bitmap is valid. In the case of a match, the index in the bitmap is invalidated and the execution flow continues. Conversely, in case of mismatch, a control-flow exception is raised. To Chapter 5. BackGuard summarize, a set bit in the map refers to a valid return pointer.

The advantage of a bitmap approach over a shadow stack is that its size is fixed at compile time. Each bit in the map identifies an executable address pointer which is generally 32 bits. As a result, the bitmap size is fixed to 3.125% of the total memory.

Finally, the bitmap approach maintains the application determinism. While this approach may induce an obvious execution-time overhead due to function activation, deactivation, and indirect backward-edge verification, the address translation is operated by fixed instructions that remain independent of the function that identifies in the bitmap.

Consequently, it has no impact on the deterministic performances of an embedded application.

Security challenges

Regarding the security, the bitmap is a memory area that acts as a checker to validate the integrity of return addresses. Unfortunately, like other memory areas such as the stack, the BSS, and the data sections it can be jeopardized by the out-of-bound vulnerability. To illustrate these issues, By default, the STM32s' stack is ascending downwards, and as the other sections located in the SRAM, the stack enforces read, write, and execute permissions.

The peripherals' memory mapping is located above the SRAM memory section of the microcontroller. These peripherals mostly include serial communications, GPIOs, and any external hardware peripherals. Of course, the peripherals are configured and accessed by embedded applications by writing and reading to their memory-mapped addresses.

Both the external RAM and external memory regions are usually dedicated to external memory and coprocessor. These memory regions are unused on the STM32 platform. The top memory regions such as the "Private Peripheral Bus" and "Vendor-specific memory" are present on every ARMv7-M processor. These regions, more specifically the "Private Peripheral Bus" region, handle the System Control Space (SCS) including the Nested Vector Interrupt Controller (NVIC), and the Memory Protection Unit (MPU), and the system reset.

Finally, it should be mentioned that the ARMv7-M architecture offers two execution modes. By default, an application runs at the highest privileges. This implies that the application can use all instructions and all processor resources. Conversely, the unprivileged mode has limited access to system registers and instructions. The unprivileged mode also restricts access to peripherals.

Following this brief discussion, it seems that a simple linear stack buffer overflow/underflow can take over an entire embedded application. First, a memory exploit can target a return address located in the stack and divert the execution flow of an application on a previously injected malicious code. Also, as the peripherals are located above the stack memory region. Their configuration, as well as the I/O of the application, can be tampered leading to undefined malicious behavior. Finally, as the flash memory enforces read, write, and execute by default, an attacker can even tamper the firmware and modify its integrity.

As a direct consequence, protecting an in-memory bitmap from a spatial vulnerability seems to be a difficult challenge. A naive technique to complicate spatial attacks is to place the bitmap in a hard-to-reach place in memory. For instance, by leveraging the read, write, execute property of the flash, the bitmap can be placed below the text section as displayed in Figure 5.5. Therefore, it would be harder to reach the bitmap using a simple out-of-bounds vulnerability located in the SRAM.

Unfortunately, just placing the bitmap section below the other sections is not enough. each peripheral accesses such that the application escalates privileges before accessing the peripheral and dropping the privileges after accessing the peripherals.

Approach

Instead of separating privileges, BackGuard proposes a more relaxed policy that still protects the bitmap. This policy is based on read-only guards (RO-Guards). These guards, displayed in Figure 5.6, cluster the boundaries of the bitmap, the stack, and the unsafe global variables in the SRAM. policy applied to the SRAM sections. DEP is also combined with a Read eXecute (RX) policy for the code section and the rodata section located in the flash of the microcontroller.

Of course, the bitmap section stays writable. Thanks to this DEP protection, an attacker may not be able to perform code-injection attacks anymore.

The second protection is called unsafe object clustering with Random Guards (Rand-Guard). This protection, displayed in Figure 5.6 is an adaptation of the Stack Smash

Protector but for bare-metal embedded system application. The protection places Rand-Guards between unsafe memory objects, code-pointers, and data-pointers. These Rand-Guards cluster overflowable objects to prevent out-of-bounds attack propagation. [START_REF] Abbasi | Challenges in designing exploit mitigations for deeply embedded systems[END_REF]. Thus an appropriate method must be implemented for random number generation.

Implementation challenges

5.3. Implementation

Implementation

BackGuard is implemented within the Clang/LLVM compiler infrastructure. It comes with secure libraries that are linked to the final executable. These libraries configure our STM32F446RE workbench MPU and generate a random number during the initialization sequence of the processor. The details of both the MPU and the random number generation is given further in the section.

The improved LLVM compiler provides bitmap protection. During code generation, the compiler identifies which function saves its return address in the memory. Then, it adds extra instruction to the application code so that vulnerable function activates and deactivates their return address corresponding bit in the bitmap. Regarding the Rand-Guards, the compiler analyses the stack frames data. It identifies vulnerable buffer that may overflow from other data. All the allocated stack frame objects are then sorted such that stack objects that may overflow are placed bellow the Rand-Guard and sensitive data such as function pointers are placed above the Rand-Guard. Finally, during code generation, the compiler changes the attribute section of overflowable global memory objects such that they cannot reach safe objects incase of vulnerability.

Compiler implementation strategy

The Clang/LLVM project is a very modular and well-documented compiler for native Regarding the compiler infrastructure, it seems that the bitmap return address protection should be implemented in the backend. Indeed, the backend is responsible for target-dependent prologue and epilogue insertion including return address register spill. Thus, one way to protect the return address with the bitmap is to implement a targetdependent machine pass that adds extra instructions per function prologue and epilogue so that every spilled return address in the memory is registered and removed from the bitmap 5.3. Implementation on purpose. Many extensive works such as [START_REF] Clements | Protecting bare-metal embedded systems with privilege overlays[END_REF][START_REF] Zhou | Silhouette: Efficient Protected Shadow Stacks on Embedded Systems[END_REF][START_REF] Almakhdhub | µRAI: Securing embedded systems with return address integrity[END_REF] have worked and implemented memory safety protection for low-end ARM-based microcontrollers in the backend. However, backend modification imposes invasive changes in the compiler internals. Also, providing security features based on backend modifications breaks flexibility. It forces developers to use a specific version of the compiler and recompiles it from the sources. Indeed, invasive backend modifications only target specific architecture. This means that the portability is low and when changing architecture, the security feature may not be implemented. Conversely, it seems that working on the LLVM IR is much more flexible than providing security at the backend level. It allows the security to be developed as a compiler plugin that can be loaded within any compiler version. Also, it does not require developers to compile their compiler from the sources. Quite the opposite, the security can be loaded in the compilation workflow of the Clang/LLVM version available from officials repositories. However, it should be mentioned that implementing the security at the LLVM IR level raises challenges; Additional IR instructions for security may be removed in backend optimizations, breaking the security.

Additional passes

To ensure flexible security, the BackGuard toolchain introduces two additional Intermediate Representation (IR) passes in the Clang/LLVM compiler workflow. These compiler passes are developed as external compiler libraries and are loaded at compilation time in LLVM as a plugin. Working on the IR provides a high level of flexibility. First, external libraries do not require any invasive internal compiler modification. Second, the security provided by the external libraries can be easily deployed on exotic architectures maintained by the various LLVM backends. Finally, the security can be easily deactivated on purpose.

Bitmap hardening pass

The first BackGuard compilation pass enforces return address bit activation and deactivation in the bitmap. As this work focuses on ARM-based microcontrollers it is important to remind the procedure call standard. Function subroutines are called using both the "bl" and "blx" instruction. These "call" instructions pass the execution flow to a subroutine and place the caller return address pointer in the ARM link register (LR). Then, depending on the fact that whether the called function is a leaf function or not, the caller return address is spilled by the compiler.

Unfortunately, the information on whether a function saves the return address in the memory is only available late in the compiler pipeline during prologue/epilogue generation.

To determine whether a function is saving its return address in the memory from the LLVM IR, the BackGuard bitmap pass iterates over every function's IR instruction to find function call. If the parsed function is not calling any function, it is considered as a leaf function. Consequently, the compiler backend may not spill its return address making the BackGuard pass skipping the function protection.

Chapter 5. BackGuard

The second challenge is to get the return address value from the IR and then perform the address translation to enable the corresponding bit in the bitmap. Usually, the return address is handled in the Link Register which is defined in the compiler backend. However, LLVM provides a specific intrinsic (llvm.returnaddress) that can be used at the IR form to manipulated the return address of a function. This intrinsic function is inlined by the BackGuard compiler pass at the beginning of each function. The returning value of this intrinsic is the return address of the function that is then translated into a bit loaded in the bitmap by classical IR instructions. According to the LLVM documentation, intrinsics are transparent to optimization passes and consequently, they preserve the BackGuard bitmap protection during the whole compilation workflow.

Random guard pass

As previously explained, the random guard pass is very similar to the existing stack protector implemented in GCC. Our random guard pass is not the major innovation of this work but it contributes to hardening embedded applications against memory exploits.

The random guard value of BackGuard is based on a random number generated during the boot sequence of the microcontroller. The details of the boot sequence are highlighted in the next sub-section.

During compilation, the BackGuard's Random Guards pass analyses each function at the IR level and identifies stack frames object that may be vulnerable to overflow issues.

The local stack frame objects are then sorted such that dangerous objects are placed bellow the Random Guard and safe objects above.

Regarding the global variables, the Random-Guard pass changes the section location of sensitive memory objects. As displayed in Figure 5.4, sensitive memory objects that are supposed to reside in the BSS or the data sections are moved into the safe BSS and the safe data sections.

Boot sequence

Both the bitmap protection and the random guard canary rely on memory protection (MPU) and random number generation (RNG). Concerning the protection of the bitmap, the Data Execution Prevention (DEP), and the code section protection, BackGuard links a secure library to the final embedded application. This library includes a set of functions that are called during the initialization sequence of the microcontroller. These functions configure the Memory Protection Unit of the microcontroller such that it protects the code section with RX, the bitmap section with RW, and the SRAM with RW permissions.

BackGuard leverages the fact that the protected memory regions can overlap. For the ARMv7-M architecture, the region with the highest number has a priority over the other region with the lowest number (e.g region 4 protection takes precedence over region 2).

Consequently, the configuration of the bitmap region takes precedence over the whole flash configuration. The configuration of the MPU is summarized in Table 5.1. [START_REF] Zhang | A survey on silicon pufs and recent advances in ring oscillator pufs[END_REF]. According to [START_REF] Holcomb | Randomness in integrated circuits with applications in device identification and random number generation[END_REF] and for the rest of the study we will consider that 20 bits of SRAM cells are enough to generate a random bit.

Implementation

Thus to generate a strong 256 bits random number, BackGuard bootloader reads 640 bytes of SRAM and passes them through an embedded BLAKE hash function [START_REF] Aumasson | Blake2: simpler, smaller, fast as md5[END_REF]. As the 640 bytes of SRAM are random and the BLAKE hash function is a cryptographic pseudorandom function, the generated 256 bits value is random. The 32 bits value of the canary is then extracted from the generated key and placed in a read-only location in the flash.

Evaluation

represents the number of addresses that can be reached by a transfer j restricted by control-flow integrity protection. It seems that if the percentage given by this formula is close to 99% the control-flow solution can be considered as fine-grained [START_REF] Walls | Control-flow integrity for real-time embedded systems[END_REF]. Conversely, a very coarse-grained control-flow protection has an AIR close to 80% [START_REF] Walls | Control-flow integrity for real-time embedded systems[END_REF].

The bitmap protection enforces indirect backward-edge integrity. As a result, forwardedges are left unprotected. To measure the impact of unprotected forward-edges and the accuracy of protected backward-edges, we first measure the BAIR (Backward-edge Average Indirect target Reduction) provided by BackGuard which does not take into account the forward-edges. Then, we measured the AIR to determine the impact of unprotected forward-edges on the overall protection.

As a reminder, the bitmap protection is a little less accurate than a regular shadow call stack. Each function can only return to an activated return call-site in the bitmap. These activated return-sites are part of the call stack of an activated function. When returning, a function can thus return to a few valid locations in its call stack.

To measure the BAIR and the impact of the little inaccuracy of the protection, a specific graph analysis algorithm is developed. The latter evaluates the worst-case valid return call site per function and the best-case valid return call site per function. For SecPump, it results in both a worst-case and best-case direct acyclic graph. Both graphs are then processed with Formula 5.1 to determine the worst-case and best-case average indirect target reduction. The results are displayed in Table 5.2. The Rand-Guard value can be leaked through a memory disclosure or with physical access.

However, its value would only be valid for a single vulnerable application thanks to the property enforced by SRAM based Physical Unclonable Function (PUFs). Thus, to be efficient and to scale multiple targets, an exploit should leak the Rand-Guard any time it targets an application. Second, the attacker can either corrupt sensitive data such as function pointers or a function return address. Unfortunately, when targeting a return address the attacker has to replace it with a valid destination on the map or target a function pointer.

The other option is that the attacker tampers the bitmap. However, the latter is deeply buried in the flash and surrounded by RO-Guard that prevents spatial attacks. Of course, the bitmap is not unreachable, one way to corrupt it is to acquire a data pointer, make it point to the target index in the bitmap, use this pointer to write the bitmap and finally corrupt an in-memory return address to redirect the execution flow on the desired location.

Although this scenario is quite likely, it is tedious and requires several primitives.

BackGuard considerably increases memory safety. Finally, as BackGuard enforces Data Execution Prevention (DEP), no malicious code can be executed in the stack. Thus, attackers should use advanced return-oriented programming gadgets to develop functional exploits.

Costs

Size overhead

The size overhead induced by BackGuard is measured in three different cases. First, the reference application is compiled with Clang/LLVM without the BackGuard protection options but with the "Os" optimization (size optimization). Second, the application is compiled with the bitmap protection only, and finally, the bitmap protection combined with the Rand-Guard. The vanilla application as a fixed code size of 29504 bytes and 32064 of total bytes in the flash. The application leaves 94% of the flash memory free.

Using the bitmap protection, any code pointers (executable address in the flash) is identified with a bit. As in-memory code-pointers are 32 bits the total size of the bitmap represents 3.1% of the flash memory. In our case, it represents 32768 additional bytes reserved in the flash. Furthermore, the additional code generated by the compiler to interact with the bitmap increases the total code application size up to 32264 bytes (9% increase). Overall the applied bitmap protection increases the application size up to 5.4. Evaluation 67592 bytes which is a 110% application code size overhead. However, it still leaves 88% of the entire microcontroller memory free. It is important to remind that the bitmap is fixed. Thus, although it induces a significant size overhead for a small application, its memory usage regarding the available memory of the microcontroller is very small (3.1%). Furthermore, the size of the bitmap is not linked to the size of the compiled application. Consequently, as long as the application does not use more than 96.9% of the microcontroller memory it should not be an issue.

Finally, the fully protected application occupies 81208 bytes of flash which represents a size overhead of 153%. Again, it leaves 85% of the microcontroller memory free. More specifically, we measured a code-size increase of 55%. This code-size increase includes the custom bootloader that initializes the random guard by reading the flash and passing the value to the BLAKE hash function, the MPU configuration, the bitmap checks, and the random guard insertion/checks. We believe that this 55% should decrease with a bigger application. Indeed, among the 55% increase, 84% represents the custom bootloader application that configures the MPU, reads the uninitiated SRAM, and hashes the random value using the BLAKE algorithm.

Execution-time overhead

Two execution-time overhead is induced by BackGuard. First, during the initialization of the microcontroller, in addition to configuring all the peripherals, initializing the stack, and copying the data of the microcontroller in the SRAM, BackGuard should initialize the bitmap, the MPU, and the Rand-Guards with the BLAKE hash function. These additional operations increase the boot-time by 48%.

To assess the average execution-time overhead after boot-time, various embedded sys-Chapter 5. BackGuard tem benchmark suites such as CoreMark [START_REF] Gal-On | Exploring CoreMark™ -A Benchmark Maximizing Simplicity and Efficacy[END_REF], Dhrystone [START_REF] Weicker | Dhrystone: A synthetic systems programming benchmark[END_REF], and various embedded benchmarks from BEEBS [START_REF] Pallister | BEEBS: Open Benchmarks for Energy Measurements on Embedded Platforms[END_REF] are compiled with BackGuard.

The average execution-time overhead induced by BackGuard is measured with optimization level 2. The CoreMark benchmark suite is configured to run up to 1000 iterations and the Dhrystone benchmark suite up to 50000 iterations.

To obtain accurate execution-time measurements we leveraged the STM32F446RE cycle counter. We developed a simple library that resets the cycle counter before performing the various benchmarks and displays its value at the end of the execution.

As mentioned earlier, several variants of BackGuard are added to the compiler. These

Discussion

This section outlines the current limitations of BackGuard and the research avenues for its improvement. As with any software defense, it is fair to state that BackGuard is not perfect protection. However, BackGuard still protects low-end microcontrollers from a wide range of trivial spatial memory attacks.

Regarding limitations, BackGuard is not well designed to support the famous "setjmp/longjmp" issue. Unlike TrustFlow which perfectly handles it, BackGuard handles it with a little bias. Indeed, the "setjmp/longjmp" functions are generally used to restore a program to a previous state. In the context of embedded system programming, "setjmp/longjmp" can be used in exception handling. The effect of the "longjmp" function is to restore the program and its stack frame to the "setjmp" point. Unfortunately, this jump breaks the classical call/return construction of a program. As a result, some functions called after the "setjmp" point may never return. For shadow call stack this might be a problem because the top of the shadow stack may not match the restored function's return address. For the bitmap, the restoration state might not be an issue, as all the whole call stack is activated on the map. Unfortunately, all functions called after the "setjmp" may never be deactivated from the map. This opens new valid target destination addresses for an attacker. One way to tackle this issue would be to deactivate the functions from which the stack frame is destroyed by the "longjmp". While not impossible, this may require to parse the call stack trace of an application before the "longjmp" and after the "longjmp".

Then, the return address of each function freed by the "longjmp" should be identified and deactivated from the bitmap. Although this process might be costly, it may worth the price if an application rarely uses "setjmp" and "longjmp".

Unlike TrustFlow, BackGuard is currently incompatible with recursion. A recursive function may call itself more than twice. As a result, after the first return, the function return pointer's corresponding bit in the bitmap is unset raising an exception at the second return. There are several ways to tackle this recursion issue. First, BackGuard can be provided with coding rules like TrustFlow that prevent the usage of recursion. Indeed, recursive function calls in low-end embedded systems may blow up the stack. Usually, the upper bound of recursive functions is difficult to predict with static analyzers and code verification tools. As a result, the usage of recursion in low-end embedded systems is inconsistent with safe development practices. To push it further, rule 16.2 of MISRA-C [START_REF] Bagnara | The misra c coding standard and its role in the development and analysis of safety-and security-critical embedded software[END_REF] for safety-critical embedded application bans the usage of recursion. Finally, recursive functions are computable by an iterative model [START_REF] Holzmann | The Power of Ten-Rules for Developing Safety Critical Code[END_REF]. In many cases, converting a recursive function into an iterative model can be achieved using a global stack completely compatible with BackGuard. Another solution to handle recursion is to use the shadow stack variant of BackGuard.

Currently, BackGuard is not implemented within multitasking real-time operating systems [START_REF] Barry | Freertos[END_REF]. Of course, managing multiple tasks is hardly possible with a single bitmap. In a low-end real-time system, two separate tasks may share multiple functions and the scenario that two tasks may concurrently access the same function is plausible. Unfortunately, it 5.5. Discussion may result in a false-positive control-flow integrity violation.

One way the bitmap approach would be compatible with a multitasking system is to develop an application where every single task does not share any function. In this case, a single bitmap may handle a whole application. Another way would be to handle a single bitmap per task. Unfortunately, a single bitmap takes up to 3.1% of the whole memory. While this size overhead is acceptable for a single bare-metal system it may increase proportionally with the number of tasks to be secured.

It seems that a shadow stack approach could be a better approach than the bitmap for multitasking embedded applications. Following this principle, each process would handle a per task shadow stack that is switched and restored by the scheduler on purpose.

Since the BackGuard compiler extensions set acts on the intermediate representation (IR) of LLVM, its transformations are architecture-independent. We extensively test the implementation of BackGuard on the ARM instruction set using an STM32 as a system workbench. However, using the Clang/LLVM compiler version 9.0.1, we were able to implement BackGuard on the RISC-V, SPARC, MIPS, x86, Aarch64 architectures making the overall defense inherently scalable. Of course, the configuration of the MPU, and the generation of a random guard may depend on the target microcontroller. They represent the only architectural dependant part of the BackGuard framework that should be adapted.

Comparison with related work

This section discusses a coherent selection of well-known software-based memory safety protection dedicated to bare-metal embedded systems. Their effectiveness, approaches, and flexibility is compared with BackGuard.

RECFISH [START_REF] Walls | Control-flow integrity for real-time embedded systems[END_REF] As BackGuard, µSSP clusters vulnerable buffers from sensitive data per stack frames.

However, unlike BackGuard µArmor does not specifically enforce control-flow integrity.

In the case of stack memory disclosure, return address pointers are unprotected allowing attackers to hijack the execution flow. Finally, µScramble is a software diversity compiler pass that mimics fine-grained address space layout randomization protection. µScramble shuffles registers, function orders, and inserts dead-code. Unfortunately, the diversity of the code generated by µScramble is limited by the size of the microcontroller and code memory leaks. The former restricts the numbers of possible morphs that can be generated by the compiler while the latter can completely de-randomize the code memory section allowing on-the-fly memory explois [START_REF] Snow | Just-in-time code reuse: On the effectiveness of fine-grained address space layout randomization[END_REF]. Also, regarding the thesis's approach, software diversity is prohibited in safety-critical devices. Finally, BackGuard is more flexible than µArmor. µArmor requires to recompile the application code before being deployed on the hardware. Also, µArmor involves several invasive backend compiler modifications while BackGuard is more flexible by operating on the IR. Finally, regarding the performances, µArmor induces less than 1% execution-time overhead on average and less than 5% size

Conclusion

This chapter proposed a flexible defense against memory-based exploits on low-end embedded systems. Low-end microcontrollers are becoming increasingly popular with the rise of the Internet of Things. They are currently integrated into exotic embedded applications ranging from connected bulbs to real-time life-critical devices. Also, lowend microcontrollers are often used as companion processors to relieve main application processors from specific tasks. Unfortunately, unlike powerful processors, the security features provided by low-end microcontrollers are less. Low-end microcontrollers do not benefit from well-known memory safety protection such as the Address Space Layout Randomization (ASLR), the Data Execution Prevention (DEP), and the Stack Smash Protector (SSP). On top of that, these microcontrollers are highly restricted in terms of execution-time, code size, and power consumption which does not ease the integration of security protections. As a result, even the most trivial linear buffer overflow vulnerability can easily be turned into a successful remote code execution exploit.

To improve memory safety, BackGuard proposes a set of compiler plugins that simplifies the integration of memory safety in low-end bare-metal microcontrollers.

Conclusion

Conclusion

Violating the control-flow integrity of an application using software exploits is at least as broad as the existing protections. During this thesis, I particularly explored the memory safety issue and its impact on wireless critical medical devices (IoMT). Interestingly, despite the numerous efforts spent at mitigating such attacks over the last 30 years, medical devices do not possess even the most basic memory safety defenses.

By reviewing the memory safety defenses state-of-the-art and the context of the Internet of Things (IoT), I exhibit that only a few concepts are suitable for critical and constrained IoMT devices. First, these devices are part of the IoT trend. They are pressured by time-to-market and costs that often take precedence over the integration of security. Besides, it seems that manufacturers of wireless medical devices are lacking security experts and connectivity opens new threats that were not present beforehand.

On top of that, medical devices are constrained by their size, real-time performances, and safety requirements making the integration of security challenging.

With the awareness of this context, we identified several criteria that should be taken into account when designing practical defenses against memory attacks in critical and constrained embedded systems. In a nutshell, these criteria highlight that memory safety in these systems should be robust, practical, safe, deterministic inducing low performance degradation and size overhead.

From the identified criteria, we developed a complete case study of efficient memory safety integration on critical cyber-physical systems. As a first contribution, we proposed SecPump, a life-critical wireless infusion pump system workbench tailored for security assessments. The aims of SecPump are manifold. Indeed, it allows us to conduct the approach of this thesis as well as to validate it. But also, the model aims to be open to the community allowing security research on cyber-physical systems in various areas that cover both hardware and software.

Then, to protect critical and constrained cyber-physical systems from memory violation attacks, we proposed two top-down approaches that led to several contributions such as TrustFlow and BackGuard. Both approaches tackle the memory safety issue from the software design-time to its run-time on the hardware.

Regarding the thesis approach, TrustFlow provides both a processor and a complete software toolchain that can be used to develop secure cyber-physical applications. Trust- Finally, the two approaches proposed in this thesis are compatible with each other.

Perspectives

We believe than a hybrid solution between TrustFlow and BackGuard would allow finegrained memory safety protection while keeping an excellent tradeoff between security, performances, and space overhead. For instance, it would be interesting to study how BackGuard can be coupled with TrustFlow to reduce the trusted memory footprint of an application. On the other hand, the bitmap protection proposed by BackGuard is something that can be implemented at the hardware level. Indeed, the bitmap could be integrated instead of the trusted memory currently implemented in TrustFlow.

At the end of the day, the IoT promises to evolve over the next few years. Future devices may require less energy, less memory consumption, and higher processing capabilities. Simultaneously, new attacks will emerge, opening new research opportunities and in particular for solutions that aim at efficiently combining the hardware along with the software. This reinforces the fact that open architectures have a bright future with many research opportunities. A Annex 1 : TrustFlow pipeline

List of Figures

A.1 Trusted memory integration

The functioning of the TrustFlow extension is explained in Chapter 4, section 4.3.1. This appendix gives little more details about the TrustFlow extension, and the changes performed within the Rocket Chip processor generator [START_REF] Asanovic | The rocket chip generator[END_REF]. All TrustFlow extensions are implemented within a Rocket core (Tile), an in-order RISC-V CPU. A Tile, such as the one displayed in The trusted memory support of TrusFlow interfaces with the Rocket core pipeline. To remind, the latter is a content-addressable memory that performs input address search against a table of stored address/data vectors. Regarding memory safety, this trusted memory can be compared to an improved shadow call stack by mostly protecting sensitive control-flow data. The trusted memory is driven by two custom instructions added to the RISC-V Instruction Set Assembly (ISA). These two instructions such as "load word secure" (lws) and "store word secure" (sws) inherit from the classical load and store instructions of the RISC-V instruction set. However, these instructions trigger the TrustFlow extension so that it stores and checks the sensitive data. An overview of the extended Rocket core is displayed in TrustFlow particularly extends the memory access stage and the write-back stage of the Rocket core pipeline. During the memory stage, the data cache is accessed by a memory access instruction and the result is then forwarded to the write-back stage which updates the register file.

During the memory access stage, the TrustFlow extension decodes the custom instructions handled in "mem_reg_inst". If custom instructions appear to be valid at this stage of the pipeline, the TrustFlow extension retrieves the address of the data that should be stored or loaded in regular memory from the output of the ALU ("io_req_bits_addr"). Furthermore, in the case of the custom store instruction, the data to duplicate in the trusted memory is handled in "mem_reg_rs2". Both "mem_reg_inst" and "io_req_ bits_addr" triggers the TrustFlow trusted TLB controller, which is detailed further in this annex.

During the write-back stage, the TrustFlow extension operates in consistency with the custom instruction. Concerning custom loads ("lws"), the output of the trusted memory ("safe_data") fetched from the memory access stage is compared with the output of the data cache ("io_dmem_resp_bit_data"). In case of discrepancy, a data-flow violation is detected. In our proof of concept, TrustFlow proposes two ways to deal with this violation. The first one generates a hardware fault stopping the execution flow of the exploited application. The other way is that the violation triggers the self-healing mechanism of TrustFlow that replaces the corrupted data by the healthy data and logs the violation in a hidden register.

Regarding custom stores ("sws"), the TrustFlow extension waits until the custom store instruction is valid at the end of the pipeline to perform the final commit of the sensitive data in the trusted memory. Indeed, if the custom store is not valid at the end of the pipeline, it means that the data storage in the main memory has not been carried out correctly. Thus the trusted memory is synchronized according to this result. XXII A.2. Trusted memory controller

A.2 Trusted memory controller

The TrustFlow's trusted memory extension is driven by a controller that follows the state machine displayed in Figure A.3. Both sws_req and lws_req events are "sws" and "lws" instruction requests performed during the memory access stage. Besides, both sws_ valid and lws_valid events are valid "sws" and "lws" instructions in the write-back stage of the pipeline. It turns out that the transitions of the finite state machine take place according to four different events spread over two stages (memory access and write-back stage). • Idle: The controller waits for a valid custom instruction to be decoded in the pipeline.

• Lookup: TrustFlow performs a lookup table in the trusted memory.

XXIII

Annex A. Annex 1 : TrustFlow pipeline -In the case of "sws" instruction, the lookup table determines the index in the TLB where the sensitive data/address vector should be stored. If the data/address vector is already in the trusted memory the lookup table returns its index. If the data/address vector is not in the trusted memory the lookup table returns a free entry.

-In the case of "lws" instruction, the matching data is forwarded to the output of the trusted memory.

• Commit: TrustFlow commits a data in the trusted memory at the index determined by the lookup table operation.

• Check: TrustFlow performs a check between the output of the trusted memory and the output of the regular memory. In case of discrepancy, TrustFlow either stops the executed program or heals the corrupted data.

A.3 Data restoration

Introducing two custom instructions and violated data replacement in the Rocket core requires to adjust the datapath accordingly. As for regular instructions, the custom instructions are subject to data hazards, stalls, and forwarding issues. For instance, when an instruction reads a register following a load that defines the same register. In TrustFlow and like in regular RISC pipeline, the hazard detection unit introduces a stall to delay the instruction that follows the custom load. Then, the forwarding unit forwards the loaded memory data back in the pipeline. We currently modified the forwarding unit and the hazard detection unit to handle custom instructions. Also, when a data violation is detected within the pipeline, the modified datapath takes care of forwarding the healed data. More simply the modified forwarding unit of the TrustFlow pipeline implements the following conditions for the load hazards: This annex details the implementation of the ARM machine bitmap pass which is part of the BackGuard compiler Framework. In the study regarding BackGuard, this pass is specifically developed to observe the impact on the performances between flexible security operated on the LLVM IR and target-specific security implementation. The details of the BackGuard compiler extension at the LLVM IR level are provided in Chapter 5, section 5.3.2. The bitmap protection variant implemented within the ARM Backend allows the BackGuard framework to benefit from a better execution-time overhead than the LLVM IR bitmap protection. In reference to section 5.4.2.2, the obtained results reveal that the execution time overhead induced by the LLVM machine bitmap pass is 50% lower than the LLVM IR protection. This is explained by the fact that the LLVM machine bitmap pass can perform architecture dependant optimizations by directly working on the assembly before code emission.

To better understand the functioning of the LLVM backend bitmap pass, this annex requires several essential points regarding the ARM Cortex-M Instruction Set Assembly (ISA) and its calling convention. The ARM Cortex-M microprocessors follow a Reduced Instruction Set Computing (RISC) design. They are 32-bit processors that provide sixteen general-purpose registers (from r0 to r15) and 32-bit aligned instructions. Besides, these microprocessors provide a sub-instruction set called the Thumb ISA. The Thumb instruction set only uses a subset of the general registers (r0-r7), and instructions are 16 bits long. Most of the current Cortex-M processors use the Thumb 2 instruction set, which is a mix between 32-bit and 16-bit instructions. The main registers involved in the ARM calling convention are summarized in Table C.1 bellow. The procedure call standard [START_REF] Earnshaw | Procedure call standard for the arm architecture[END_REF] for the ARM architecture details how subroutines are called, how they return, and finally how the registers in Table C.1 are involved. Both "bl" (branch and link) and "blx" (branch and link exchange) instructions are used to call XXX a subroutine. These instructions pass the execution flow to a subroutine and put the caller return address pointer in the link register (LR). In a program, each function has a prologue and an epilogue. Function prologue and epilogue have the effect of setting/destroying a new stack frame and spilling/restoring the caller registers. To ensure a function return, we denote two types of instruction patterns that can be generated by the compiler. If the return address is previously spilled from the link register to a stack frame during the prologue, the ARM compiler uses a multiple load instruction to both places the return address in the program counter register and restore the spilled registers. On the contrary, if a return address handled in the link register is never spilled, the ARM compiler uses a branch exchange ("bx") instruction to branch to the return destination target.

Following the calling convention of the ARM instruction set, it follows that every function that saves the link register in a stack frame should be secured using the bitmap. On the other hand, functions that keep return addresses in the link register are not vulnerable to memory attacks. In order to protect functions that spill the link register, one challenge is to modify the way they are generated by the compiler. During compilation, and especially in the back-end, the compiler is aware of which functions spill its link register. These functions are called leaf function (e.g functions that make no calls). From this analysis, the compiler can generate a specific prologue and epilogue that registers/checks the link register using the bitmap.

The machine bitmap pass modifies the ARM calling convention. More precisely the LLVM ARM backend prologue and epilogue generation passes are modified and a custom machine passes in introduced within the compilation workflow. The resulting code generated by the compiler is displayed in Figure C The "__bitmap_reg__" routine is a couple of instructions that set the link register in the bitmap using the r4 register as an argument. Likewise, the "__bitmap_chk_ _" routine is used to check the integrity of the spilled link register using the bitmap. Both jump tables are constructed by the compiler backend during code generation. We decided to use the variable register r4 as an argument for the assembly tables. Indeed, at the beginning/end of each function, the r4 register is never live. Consequently, this register can be used to perform operations without inducing any hazards in the following XXXI Annex C. Annexe 3 : LLVM ARM backend bitmap pass instruction flow of the function. Naturally, the r4 register can be used by a called function. The latter is thus both saved and restored by the modified compiler prologue and epilogue. Choosing to use the r4 saves the spill of several registers.

During the function epilogue, the compiler machine passes leverage the LLVM stack frame info to retrieve the position of the saved link register in the local stack frame. Then, the compiler generates an instruction to load the return address from the stack frame to the r4 register. Once again this register is used by the jump table to verify and de-register the return address.

The machine bitmap pass is implemented immediately after prologue and epilogue insertion and before the second instruction scheduling pass. More specifically, the machine bitmap pass is implemented just before the ITBlockPass. This pass is an optimization that leverages the IT instruction to specify assembly condition code. As some function returns are conditional the ITBlockPass includes these return instructions within an IT block. We leverage this feature to include the bitmap checks within IT blocks so that bitmap checks are conditional if returns are conditional as well.

As a final note, we also implemented a "Machine bitmap pass" that directly includes the tables' instructions within functions' prologue and epilogue. This implementation required heavy modifications to the backend, and unfortunately, we came to the conclusion that this had the effect of considerably increasing the size of an application for very little gain in execution time.

Résumé

Cette thèse traite de la problématique des corruptions de mémoire dans les dispositifs médicaux vitaux. Au cours des dernières années, plusieurs vulnérabilités telles que les exploits de mémoire ont été identifiées dans divers dispositifs connectés de l'Internet des objets médicaux (IoMT). Dans le pire des cas, ces vulnérabilités permettent à un attaquant de forcer à distance une application à exécuter des actions malveillantes. Si de nombreuses contre-mesures contre les exploits logiciels ont été proposées jusqu'à présent, seules quelques-unes d'entre elles semblent convenir aux dispositifs médicaux. En effet, ces dispositifs sont contraints de par leur taille, leurs performances en temps réel et les exigences de sûreté de fonctionnement, ce qui rend l'intégration de la sécurité difficile. Pour répondre à ce problème, la thèse propose deux approches. Toutes deux abordent la question de la sécurité de la mémoire depuis la conception du logiciel jusqu'à son exécution sur le matériel. Une première approche suppose que les défenses peuvent être mises en oeuvre à la fois dans le matériel et dans le logiciel. Cette approche aboutit à TrustFlow, une structure composée d'un compilateur capable de générer un code sécurisé pour un processeur modifié. Ce processeur peut prévenir, détecter, enregistrer et auto-guérir les applications critiques victimes d'une attaque mémoire. La seconde approche considère que le matériel est immuable. Selon cette contrainte, les défenses ne reposent que sur le logiciel. Cette seconde approche aboutit à BackGuard, un compilateur modifié qui renforce efficacement les applications embarquées tout en assurant l'intégrité du flot d'exécution.

Mots-clés :

IoMT, sécurité, corruption de mémoire, intégrité du flot d'exécution.

Abstract

This thesis deals with the memory safety issue in life-critical medical devices. Over the last few years, several vulnerabilities such as memory exploits have been identified in various Internet of Medical Things (IoMT) devices. In the worst case, such vulnerabilities allow an attacker to remotely force an application to execute malicious actions. While many countermeasures against software exploits have been proposed so far, only a few of them seem to be suitable for medical devices. Indeed, these devices are constrained by their size, real-time performances, and safety requirements making the integration of security challenging. To address this issue, the thesis proposes two approaches. Both address the memory safety issue from the software design-time to its run-time on the hardware. A first approach assumes that memory defenses can be implemented both in hardware and software. This approach results in TrustFlow, a framework composed of a compiler able to generate secure code for an extended processor that can prevent, detect, log, and self-heal critical applications from memory attacks. The second approach considers that hardware is immutable. Following this constraint, defenses only rely upon software. This second approach results in BackGuard a modified compiler that efficiently hardens embedded applications while ensuring control-flow integrity.

Keywords :

IoMT, security, memory corruption, control-flow integrity

Figure 2 Figure 2 :

 22 Figure 2 displays an overview of a closed-loop wireless insulin pump. Three major

1. 1 .

 1 Figure 1.4: Control-flow graph

  With the emergence of Data Execution Prevention (DEP), code injection attacks became less powerful. Given this, attackers rapidly demonstrated new attacks based on code-reuse to circumvent DEP. These attacks force unexpected executable control-flow paths in an application avoiding any malicious code execution in data areas. A simple code-reuse attack is displayed in Figure 1.8. The stack memory area is snapshotted in vertex 3 which suffers from a memory vulnerability.

Figure 1 . 8 :

 18 Figure 1.8: Control-flow diversion

Figure 1 .

 1 Figure 1.11 summarizes the various attacks previously discussed. To remind, an attack often occurs in two stages. The first stage is the corruption of in-memory data. This data, may or may not be a control-flow data. The second stage is the execution of the payload that diverts the normal behavior of the target system. In Figure 1.11, a code injection attack (control-flow violation) diverts the vertex 3 to A, then B (A and B represents maliciously injected code). Equally, a code-reuse attack redirects the execution flow from vertex 2 to gadgets located in vertex 5, then 7. Finally, the Figure displays a data-oriented attack that forces the application to take the path to vertex 4 instead of vertex 6.

Figure 1 . 11 :

 111 Figure 1.11: Memory safety attacks

1. 3 .

 3 Existing Defenses over time. The following sections explore these various protection mechanisms regrouped into 4 sections such as control-flow integrity, heuristic defenses, software diversity, and data-flow integrity.

  . A label is a unique value that can be used to identify a vertex in a control-flow graph. During the execution, it is possible to verify the destination label value of each transition to ensure its validity. Any deviation from the original control-flow graph results in an invalid label destination location that terminates the program. To assign a unique label to each vertex, one solution is to inline it in the assembly code of its corresponding function or basic block of code. Due to the immutability of the code (text section) in a program, the label cannot be tampered by any memory-based attacks. Figure 1.13 displays a pure software label-based backward-edge control-flow integrity protection.

Figure 1 .

 1 Figure 1.13: Label-based control-flow integrity

  striction" often requires the help of an external component called a branch monitor. The main purpose of a branch monitor is to analyze each indirect control-flow transfer based on a certain security policy. If an indirect branch breaks the security policy enforced by the branch monitor, an exception is raised. Figure 1.15 displays a control-flow graph instrumented with a branch monitoring protection.

Figure 1 .

 1 Figure 1.15: Branch monitoring

1. 3 . Existing Defenses 1 . 3 . 1 . 4

 31314 Trampoline enforced control-flow integrity As control-flow attacks leverage indirect control-flow transfers, one mitigation is to check their destination using an intermediate trampoline. The protection consists of introducing an intermediate routine (trampoline) between an indirect branch and its destination address. Every indirect branch is first redirected to a trampoline that verifies the destination address, validates it and, redirects the execution flow to the expected function.Figure 1.16 displays the principle on indirect forward-edges.

Figure 1 . 16 :

 116 Figure 1.16: Indirect branch verification

Figure 1 .

 1 [START_REF] Scott | Remote Code Execution on the Smiths Medical Medfusion 4000[END_REF] illustrates a simple software diversification technique. Two instances of the same C code are represented in memory. However, the two applications do not have the same structure. The order of the functions in memory is different, and within the functions, the order of the basic blocks is different. It follows that the addresses of the gadgets found in the memory of both programs may be different. While Figure1.18 only displays two diversification techniques such as function and basic block shuffling, the state-of-the-art of Per Larsen et al.[START_REF] Larsen | SoK : Automated Software Diversity[END_REF] highlights other software diversification techniques such as instruction substitution, instruction reordering, and register substitution. At last, the state-of-the-art even mentioned some advanced obfuscation techniques such as control-flow flattening and opaque predicates to diversify software.

Chapter 1 .

 1 Figure 1.18: Software diversification

  et al. uses a Message Authentication Code algorithm (MAC) to protect the sensitive control-flow data stored in memory. The CCFI compiler ensures that each time a controlflow data is stored in memory its MAC is computed using the cryptographic extension accelerator of the Intel processor and is stored alongside. In the same way, each time a control-flow data is required by a program, its MAC is verified. According to[START_REF] Mashtizadeh | Cryptographically Enforced Control Flow Integrity[END_REF], the MAC key is randomly generated at the program start and stored in registers that CCFI compiler reserves. The security of CCFI relies on two assumptions. First, the code never leaks the key because the compiler enforces that the instructions of the program never use the reserved registers. Second, attackers cannot execute the code that accesses the reserved registers because they would have to break control-flow in the first place. CCFI 1.3. Existing Defenses induces an average of 23% execution-time overhead on the SPEC2006[START_REF] Henning | Spec cpu2006 benchmark descriptions[END_REF] Benchmark suite for the programs that are only written in C. Although this overhead is high, the cryptographic approach ensures fine-grained control-flow integrity by protecting sensitive control-flow data. It worth mentioning that the solution does not tackle pure data-flow integrity but can be used to it by extending the compiler.

Figure 1 .

 1 Figure 1.19: Fat Pointer

Figure 1 .

 1 Figure 1.21 displays a simple tagged memory with three in-memory adjacent objectsand their respective tags. These tags are displayed using colors such as green, yellow, and red. In Figure1.21, a store instruction is associated to object A and a write instruction is associated with object B. By controlling the offset of the store instruction, an attacker may use it to tamper object B. However, when object B is accessed with the read instruction, the maliciously modified tag of object B does not match the tag of its accessing instruction raising a data-flow violation.Data Flow Integrity (DFI)[START_REF] Castro | Securing software by enforcing data-flow integrity[END_REF] extends the Phoenix compiler framework introduced by Microsoft Research to enforce data protection. DFI enforces data integrity in three steps. First, the compiler performs an inter-procedural reaching definition analysis to determine the data-flow graph of a program. During this analysis, the compiler extracts all the data that may be read by an instruction, these instructions are said to use the value. Then, for each data read, the compiler determines the set of all instructions that

Contents 2 . 1

 21 Problem statement . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.1 Why critical medical devices are insecure? . . . . . . . . . . . . . 2.1.2 Why current defenses are not implemented in medical devices? . 2.2 Important memory safety criteria for medical devices . . . . . 2.3 Approaches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  the case of Windows and Linux. By showing attacks and innovative defenses under Linux, researchers have contributed to the advancement of knowledge and concepts that have allowed Windows to improve its security. This does not mean that an open-source system is more secure than a closed-source system, or that all closed-source systems have to be open-source to be more secure. What is important is to have open-source systems close enough to closed-source systems that allow researchers to propose new security concepts applicable to closed-source systems. Unfortunately, medical device security is not open to research. Few open-source life-critical devices are available to researchers discouraging them contribute. Thus, the lack of openness to research and the lack of open-models remains an impediment to the improvement of critical medical systems security. One way to change the situation would be to provide researchers with open-source systems close to real systems.

Figure 2 .

 2 Figure 2.1 displays an overview of both generative approaches.

Contents 3 . 1 75 3. 2 77 3. 3 81 3. 3 . 1 A 81 3. 3 . 2 82 3. 3 . 3

 31752773813181328233 Finally, SecPump aims at being open-source. Its assets over the existing work are presented in the last section of the Chapter. Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Open Source Medical Devices . . . . . . . . . . . . . . . . . . . . SecPump . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . wireless pump model . . . . . . . . . . . . . . . . . . . . . . . SecPump software model . . . . . . . . . . . . . . . . . . . . . . SecPump variants . . . . . . . . . . . . . . . . . . . . . . . . . . 88 3.4 Security Assessments . . . . . . . . . . . . . . . . . . . . . . . . . 90 3.4.1 Software Threats . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 3.4.2 Hardware Threats . . . . . . . . . . . . . . . . . . . . . . . . . . 91 3.5 Comparison with other works . . . . . . . . . . . . . . . . . . . . 93 3.6 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 3.1. Motivation

Figure 3 .

 3 1 displays an overview of the Open-Source Syringe pump. First, The Raspberry Pi hosts a web page accessible from the network. This web interface allows an operator to calibrate the syringe, adjust its position, and define the injection speed. Once set up, the control of the syringe is achieved with a python script running on Raspbian the Raspberry Pi GNU/Linux open-source operating system. The latter interfaces between the drivers and the mechanical parts of the system to perform an accurate control. The mechanical parts of the syringe integrated with a stepper motor must be printed using an open-source RepRap 3-D printer. In comparison with commercial pumps, the open-syringe project claims that the entire system can be built by spending less than 5% of the price of a real commercial pump.

Figure 3 . 1 :

 31 Figure 3.1: Open-Syringe

Figure 3 . 2 :

 32 Figure 3.2: OpenAPS closed-loop

Figure 3 .Figure 3 . 3 :

 333 Figure 3.3 displays how the SecPump system models the behavior of a wireless insulin pump.

Figure 3 . 5 :

 35 Figure 3.5: SecPump manual injection sequence

Figure 3 . 10 :

 310 Figure 3.10: SecPump automatic injection sequence

ure 3 .

 3 [START_REF] Kim | Hacker can send fatal dose to hospital drug pumps[END_REF]. In Figure3.11, the blue curve represents the amount of insulin injected by the pump while the red curve represents the simulated blood glucose. Initially, the blood glucose is high and brought back to the setpoint around 85mg/dL by the PID in less than 4 hours. Finally, regardless of the magnitude of a rise in glucose following a simulated meal, the PID regulates the insulin injection so that the glucose level is below 140mg/dL at least two hours after the meal[START_REF] Care | Classification and Diagnosis of Diabetes: Standards of Medical Care in Diabetes-2020[END_REF].

Figure 3 . 11 :

 311 Figure 3.11: PID blood glucose regulation Kc=-0.07, tauI=1, tauD=1.20

Finally, this work

  aims at being released as an open-source platform for the community. We believe that such a minimalist and inexpensive platform may promote security innovations in life-critical medical devices. It may open new security opportunities different from personal computers by considering additional issues such as safety and real-time constraints. Final note: The wireless model of the pump presented in this chapter has significantly evolved throughout the thesis and culminated in the final version incorporating a PID insulin controller coupled with a diabetic simulator. SecPump has been published in the 2020 IEEE Embedded Systems Letters journal [149]. The STM32-based version Chapter 3. SecPump of SecPump also inspired the design of a lightweight cryptographic AES, resistant to side-channel attacks. The related paper: "CONFISCA: an SIMD-based CONcurrent FI and SCA countermeasure with switchable performance and security modes" will soon be submitted for publication. SecPump-BLE-RT also served as a security demonstration support for the "BackFlow: Backward Edge Control Flow Integrity Enforcement for Low End-ARM Real-Time Systems" publication at the University Booth Demonstration at IEEE DATE 2020. Finally, within the Serene IoT framework, the security analysis performed on SecPump contributed to the LCIS security analysis of WP2. The pump model will be open-sourced on Github at the end of this thesis. This will include the code of the platform, the documentation, and the security analysis. 4.1. Motivation

4. 2 . Approach 2 .

 22 While embedded systems are also prey to hardware attacks. Hardware attacks are out of the scope of this work. It considers that software attacks are operated remotely

Figure 4 .

 4 1 displays the overview of the approach in line with section 2.3.

Figure 4 . 1

 41 Figure 4.1: TrustFlow top-down approach

Figure 4 . 2 :

 42 Figure 4.2: TrustFlow Trusted Environment Concept

  analyzer. This tool statically estimates the trusted memory cost of a program before any implementation on the real hardware. As a result, the static analyzer informs developers early in the design stage about the cost of the security as well as the validity of its application regarding the hardware environment. Regarding critical devices, this tool allows to formally prove that an application fits the hardware security support. The TrustFlow toolchain workflow is displayed in Figure4.3.

Figure 4 . 3 :

 43 Figure 4.3: TrustFlow Toolchain Concept.

  TrustFlow hardware extension is a trusted memory driven by a modified pipeline. Besides, TrustFlow integrates a custom hardware correction algorithm that heals systems from detected memory-based attacks. At the software level, an extended version of the LLVM compiler is provided. This compiler provides instruction-level separation support for sensitive data access. During code generation, the compiler identifies each sensitive data. At instruction selection time, the compiler uses the custom instructions to secure sensitive data-flow (code pointers). The critical application code can be analyzed using the custom LLVM based static analyzer. The latter determines the maximum amount of live sensitive data used by an application.

Figure 4 . 4 displaysFigure 4 . 4 :

 4444 Figure 4.4: Trusted Memory Custom Load and Store.

Figure 4 . 5 :

 45 Figure 4.5: Simplified RISC-V Core with the TrustFlow Extension.

Figure 4 .

 4 7 displays on the left various compiled functions with their trusted memory costs. For instance, the vertex (function) 1 cost 3 entries in the TLB and calls vertex 2, 3, and 4.

Figure 4 . 7 :

 47 Figure 4.7: Static Analyzer.

Figure 4 . 8 :

 48 Figure 4.8: Trusted Memory Footprint.

ure 4 . 9 .

 49 The RadonAna application is executed 20 times with different sinogram data files. The worst dynamic case is displayed in Figure4.9.

Figure 4 . 9 :

 49 Figure 4.9: Dynamic versus Static Evaluation.

  activates a unique function label in an isolated memory area. When the function terminates, another custom instruction deactivates the label from the trusted memory, and the processor checks that the target return address is part of an active function. Compared with TrustFlow, HAFIX does not enforce forward-edge CFI, leaving room function pointer hijacking attacks. In terms of backward-edge CFI, HAFIX always ensures that a function returns to an active function which is part of the call stack. Unfortunately, it does not guarantee that the function main return to its most recent caller which Trust-Flow does. While execution-time overhead of both HAFIX and TrustFlow is very low, HAFIX has an advantage over TrustFlow. HAFIX overcomes the regular shadow call stack size limitation thanks to label activation/deactivation. However, HAFIX proposes special instructions just to tackle "setjmp" and "longjmp". TrustFlow uses an innovative technique based on the stack pointer value to maintain stack coherency. Finally, HAFIX

  According to the assessments, TrustFlow can ensure complete fine-grained controlflow integrity through fine-grained data-flow integrity with less than 1% execution-time overhead and a trusted memory with less than 100 entries. The contribution comes with strong compiler support, compliant with all C standards, making the integration of security simple and compatible with incremental tests/compilation. Finally, TrustFlow provides a novel data recovery process for corrupted data that maintains execution flow determinism. In closing, TrustFlow focuses on the first stage of spatial exploitation techniques. Two popular security threats such as temporal exploits and information leakage exploits still lack enough research. These two popular exploits constitute open issues and further TrustFlow improvements.Final Note: TrustFlow is the result of several previous works achieved on hardware shadow stacks. Its origin goes back to Speculoos[START_REF] Bresch | A red team blue team approach towards a secure processor design with hardware shadow stack[END_REF][START_REF] Bresch | Stack Redundancy to Thwart Return Oriented Programming in Embedded Systems[END_REF], a hardware shadow stack based on the OpenRISC architecture. Speculoos is a hardware shadow stack driven by a finite state machine, dedicated to low-end single task application. Unlike TrustFlow, Speculoos does not require any software support. For space reasons, Speculoos architecture is not detailed in this thesis. However, Speculoos has been published at the 2nd International Verification and Security Workshop, IVSW 2017[START_REF] Bresch | A red team blue team approach towards a secure processor design with hardware shadow stack[END_REF]. Moreover, further results of the 4.7. Conclusion Speculoos architecture have also been published in the IEEE Embedded Systems Letters journal in 2018[START_REF] Bresch | Stack Redundancy to Thwart Return Oriented Programming in Embedded Systems[END_REF]. TrustFlow leverages the limitation of Speculoos and results in finer protection and more advanced concepts than Speculoos. The TrustFlow contribution has been published in the 2019 IEEE Computer Society Annual Symposium on VLSI (ISVLSI)[START_REF] Bresch | TrustFlow : A Trusted Memory Support for Data Flow Integrity[END_REF]. The original software support was based on the GCC[START_REF] Griffith | GCC: The Complete Reference[END_REF] compiler, then, the work moved to the Clang/LLVM compiler. The trusted memory management has also been improved with the hardware garbage collector. The final TrustFlow framework has been accepted as a journal paper at the ACM Transactions on Embedded Computing Systems in May 2020[START_REF]TrustFlow-X: A Practical Framework for Fine-Grained Control Flow Integrity in Critical Systems[END_REF].

Figure 5 . 1 :

 51 Figure 5.1: BackGuard top-down approach

Figure 5 . 2 :

 52 Figure 5.2: Control Flow Guard

Figure 5 . 3 :

 53 Figure 5.3: BackGuard bitmap concept

Figure 5 .Figure 5 . 4 :

 554 Figure 5.4: ARMv7 memory layout

Figure 5 . 5 :

 55 Figure 5.5: Bitmap memory position

Figure 5 . 6 :

 56 Figure 5.6: BackGuard protections

  languages such as C/C++. The way LLVM is architected makes it easy to implement additional compiler passes. A global overview of the Clang/LLVM compiler infrastructure is displayed in Figure5.7. One can see that the compiler is divided into several components that drive the compilation flow from C/C++ source codes to the final object-assembly files. In Figure5.7, the compilation workflow starts with the Clang front-end. The latter translates native languages into a Clang Abstract Synthax Tree. The front-end ends by generating an Intermediate architecture-independent Representation (IR). The IR representation is strongly typed in a static single assignment form providing an infinite set of virtual registers. Briefly, each variable in the intermediate representation form is only assigned once and every variable is defined before it is used. As displayed in Figure5.7, the Intermediate Representation can be independently optimized and instrumented by the middle-end with the optimization tool "opt". An interesting feature provided by LLVM is that compiler passes working on the IR can be introduced in the compilation workflow on-the-fly. In other words, additional IR passes can be introduced as external plugins to the compiler without modifying its internals.

Figure 5 . 7 :

 57 Figure 5.7: Clang/LLVM compilation workflow

Figure 5 . 8 :

 58 Figure 5.8: Exploit workflow

Figure 5 .Figure 5 . 9 :

 559 Figure 5.9 recapitulates the memory occupation of each compiled version of the protection. One can see that the more the application code increases, the more the occupation of the bitmap is reduced. This is because the bitmap is fixed and thus only the application code percentage is expected to grow. The reasoning remains the same for the memory occupation repartition of the full-protected version. Since the bitmap and the bootloader are fixed their memory sized percentage occupation tends to decrease in favor of an application code increase.

  variants include a backend implementation of BackGuard and a shadow stack variant of BackGuard. They allow them to be compared with the IR implementation of the original bitmap. The backend implementation of BackGuard is a machine pass that constructs the bitmap registration/un-registration after the prologue and epilogue insertion. This pass is completely compatible with the IT Block optimization pass performed by the ARM compiler backend (for more details about this machine bitmap, we refer the reader to Annex C). The shadow stack variant operates on the intermediate representation (IR). The execution-time overhead results are displayed in Figure 5.10.

Figure 5 .

 5 Figure 5.10: BackGuard benchmarks The Y-axis represents the execution-time overhead percentage, the X-axis represents the benchmark suite

Flow

  proposes an efficient hardware-based secure environment that tracks the integrity of sensitive data in real-time. More precisely, TrustFlow extends the RISC-V Instruction Set Assembly with additional secure instructions and trusted memory. These secure Conclusion instructions are used to manipulate sensitive data and protect them using the trusted memory. The latter acts as an enhanced shadow stack able to protect both backwardedges and forward edges while remaining fully compatible with "setjmp" and "longjmp".Besides, TrustFlow leverage the trusted memory to detect memory violations, log them, and heal the corrupted data in hardware without interrupting the application executionflow. In other words, TrustFlow is engineered to continue to function correctly even if under memory-based attacks. The results demonstrated that the TrustFlow environment induces a negligible execution time overhead with a reasonable trusted memory depth. At design-time, TrustFlow comes with a practical compiler toolchain. This compiler generates a secure code that enforces instruction separation between sensitive data that use the trusted memory and non-sensitive data that remain in the regular memory.Unlike TrustFlow, BackGuard assumes that hardware is immutable and memory safety can only be implemented at the software level. Thus, BackGuard only provides a secure software toolchain that can be included in the software development cycle of cyber-physical systems. The aim of BackGuard is to demonstrate that memory defenses are feasible in embedded applications even if the hardware does not enforce specific support. Besides, BackGuard aims at being highly flexible targeting a wide range of Instruction Set Assembly. To do so, BackGuard leverage the LLVM Intermediate Representation to construct a bitmap-based backward-edge control-flow integrity protection coupled with in-memory guards. At compilation-time BackGuard separates sensitive memory objects from unsensitive one using random guards. Besides, BackGuard protects in-memory return addresses using an isolated bitmap. With BackGuard, we proved that practical and efficient memory defenses are feasible for off-the-shelf microcontrollers without relying on invasive hardware modifications. In comparison with TrustFlow, BackGuard is more flexible. As it only relies on the software it provides less security accuracy than TrusFlow. Our measurements showed that BackGuard induces around 5% execution-time overhead but requires at least 5% of a microcontroller memory.As a result, both approaches seem adapted to secure constrained and critical IoMT devices. They induce low-performance degradation (both execution-time and size), they are robust, deterministic, and practical to use and implement by non-security experts.PerspectivesPerspectivesThis thesis opens new prospects, particularly in the security of constrained and critical embedded systems. Regarding microprocessors, the results of the TrustFlow's trusted memory are encouraging. They demonstrate that a reasonable trusted memory can provide fine-grained control-flow integrity without degrading the execution-time performances. As a direct consequence, we believe that the TrustFlow concept can be implemented in the next generation of low-end microcontrollers dedicated to the IoT. Of course, further research would be required to integrate TrustFlow with a multi-tasking system. In particular, the TrustFlow trusted memory should be optimized to accommodate context switches. We believe that some research in Direct Memory Access (DMA) should be done to quickly save and restore the trusted memory when context switches occur. Also, it would be interesting to study the feasibility of coupling TrustFlow with software isolation mechanisms. Indeed, in the context of a multi-tasking system, it is better to prevent untrusted tasks from using the trusted memory. At the software level, this thesis shows that the implementation of security no longer requires detailed knowledge of the hardware by the developer. For instance, the TrustFlow compiler automates code generation preventing any security implementation mistakes. Of course, the TrustFlow compiler is a proof of concept and may require much more testing and research to refine the definition of critical data and the selection of according secure instructions. Beyond TrustFlow, the use of open architectures such as RISC-V or open-RISC opens new possibilities in all fields of innovation. These open architectures allow customizing processors and System on Chipfor specific applications' requirements. Also, fitted with compilers and operating system extensions, these architectures allow designing highly efficient systems.BackGuard also opens new perspectives regarding the software security of low-end embedded systems. BackGuard demonstrated that memory safety can be integrated within embedded applications even if a microcontroller does not have dedicated hardware memory safety primitives. Although full software security support is less efficient than a combination of both hardware and software, BackGuard stills harden memory exploits, improving the overall security. Besides, BackGuard aims at keeping a sufficient trade-off between security, performance, and code-size overhead. The latter induces around 5% execution-time overhead which is suitable for most existing embedded systems. In closing, BackGuard leverages the LLVM intermediate representation to generate memory safety protected code. This makes BackGuard multi-architecture compliant and flexible. Further research directions plan to study the existing architecture that can be covered by BackGuard.

  Figure A.1: Rocket Tile

  Figure A.2: TrustFlow pipeline

Figure A. 3 :

 3 Figure A.3: Trusted memory controller state-machine

  Figure A.4 displays a non-handled data hazard.

Figure A. 4 :

 4 Figure A.4: Data hazard example

  Figure A.5 displays the stall and forward case handled by TrustFlow.

Figure A. 5 :

 5 Figure A.5: Data hazard resolution

Figure B. 3 :

 3 Figure B.3: TrustFlow generated Code

Figure C. 1 :

 1 Figure C.1: BackGuard Machine pass generated Code

  .13 displays inaccurate protection.

	Indeed, functions B and C are both calling the function D. Thus, functions B and C are
	sharing the same label B as an identifier giving function D two different valid targets.
	This makes the presented label-based solution coarse-grained. More precisely, label-based
	control-flow integrity suffers from several constraints. First, the protection is based on
	the accuracy of the control-flow graph. Although it is easy to state that a called function
	will always return to its caller, it is much more difficult to obtain an accurate control-flow
	graph in the presence of indirect forward-edges. Indirect forward-edges are the result of
	function pointers. It is statically impossible to determine all the point-to set of this type
	of pointers and therefore to correctly inline labels. On top of that, embedded systems
	frequently use interrupts to handle specific routines. An interrupt can be triggered at any
	time and any location during the execution. Therefore, it is impossible to determine its
	return point by only using static analysis. The usage of interrupts represents a strong
	security limitation for label-based control-flow integrity.

Table 1 .

 1 More specifically, Table1.1 considers protection to be modular when they are compatible with incremental compilation. It also considers protection to be deterministic when the extra cost induced by the security is always the same given a program and an initial state. Finally, the execution-time overhead and size overhead represents the costs of the security. Unfortunately, few countermeasures provide a consumption analysis, this is why Table1.1 does not include these specific results.

			Protection	Implem.	Costs
	Name	Type		Modularity Deterministic
			BW FW Soft Hard	Exec	Size
	Abadi [68]	Labels	CG CG		+16%	+8%
	Abadi [68]	Labels+SCS	FG CG		+21%	N/A
	CET [75]	SCS+Labels	FG CG		N/A	N/A
	HCFI [78]	SCS+Labels	FG CG	P	<1%	N/A
	SmashGuard [81]	SCS	FG		<5%	N/A
	HAFIX [82]	Labels	FG		<2%	N/A
	HAFIX+ [76]	Labels	FG		+1.75% +13.5%
	BB-CFI [83]	Branch Monitoring FG CG		<1%	<209kB
	BBB-CFI [84]	Branch Monitoring FG CG		0.13%	13%
	C-FLAT [86]	Branch Monitoring FG CG		<72%	N/A
	Lo-FAT [89]	Branch Monitoring FG CG		2%	N/A
	bin-CFI [69]	Trampoline	CG CG		+4.29% +139%
	MoCFI [77]	Trampoline	FG CG		<10%	N/A
	LLVM-CFI [92]	Trampoline	FG		<6%	N/A

1 considers a security policy as fine-grained (FG) if a protected branch always targets the expected destination with 100% accuracy. Otherwise, Table

1

.1 considers the policy coarse-grained (CG). Besides, Table

1

.1 considers whether the implementation of the protection is either achieved at the software level, the hardware level, or both.

Table 1.1: Control-flow integrity policies CG: Coarse-grained, FG: Fine-grained, N/A: Not Available

The other elements in Table

1

.1 refer to the assets of the C programming language exposed in section 1.1.1. Indeed, Table

1

.1 evaluates whether the various control-flow Chapter 1. Background integrity protections are modular, deterministic, efficient with both a low executiontime and size overhead.

Table 2

 2 State of the Art Synthesis attack. In comparison with Table 1.1, Table 1.2 protection's column summarizes the number of heuristic metrics used by the heuristic engine to detect attack signatures. The other columns remain the same as Table 1.2.

		Table 1.2: Heuristic defenses policies
	Name	Enforced metrics	Implem.	Transparent Modularity Deterministic	Costs
			Soft Hard		Exec	Size
	kBouncer [97]	1			+6%	N.A
	ROPGuard [99]	6			+0.5% N.A
	ROPecker [100]	3			+2.6% N.A
	SCRAP [101]	1			<2%	N.A

summarizes the heuristic defenses exposed in the state of the art. Globally, heuristic defenses all work on the same principle such as recognizing attack signatures. These defenses use various heuristic metrics to determine the risk of a system being under 1.4.

One asset of heuristics is that they often require a few binary changes to be effective.

Heuristics are transparent to protected programs and thus, fully modular and compliant with most of the C standards exposed in section 1.1.2. Besides, Table

2

reveals that heuristic engines induce low execution-time overheads. For purely software protection this low overhead can be explained by the fact that

[START_REF] Pappas | kbouncer: Efficient and transparent rop mitigation[END_REF][START_REF] Fratrić | ROPGuard : Runtime Prevention of Return-Oriented Programming Attacks[END_REF][START_REF] Cheng | ROPecker : A Generic and Practical Approach For Defending Against ROP Attack[END_REF]

often trigger the heuristic engine in specific cases such as dangerous function calls. For hardware-based protections the heuristic engine is fully integrated within processors' architecture, operating in parallel with the monitored program. This implies a very low execution-time overhead

[START_REF] Kayaalp | SCRAP : Architecture for Signature-Based Protection from Code Reuse Attacks[END_REF]

.

Regarding security, heuristic protections do not enforce any specific control-flow integrity policy. An attacker can still violate the application's control-flow graph or attempt data-oriented attacks. Also, like anti-virus, heuristic protections are highly vulnerable to memory-based attacks combined with evasion techniques. With knowledge of the heuristic detection algorithm, an attacker can craft an attack that mimics a normal behavior for the heuristic engine. For instance, the most heuristic analysis aims at detecting code-reuse attacks based on the number of branches executed by a program in a short time window and the number of instructions between these branches. To thwart heuristic defenses, researchers demonstrated that introducing intermediate long gadgets in a Return-Oriented Programming chain is efficient at tricking heuristic engines

[START_REF] Kayaalp | SCRAP : Architecture for Signature-Based Protection from Code Reuse Attacks[END_REF]

. Also, as revealed in section 1.3.1.4, most heuristics offer incomplete protection. For instance,

[START_REF] Pappas | kbouncer: Efficient and transparent rop mitigation[END_REF][START_REF] Fratrić | ROPGuard : Runtime Prevention of Return-Oriented Programming Attacks[END_REF][START_REF] Cheng | ROPecker : A Generic and Practical Approach For Defending Against ROP Attack[END_REF]

do not prevent Jump-Oriented Programming attacks. To push it further, recent research demonstrates that signal-return oriented programming attacks

[START_REF] Bosman | Framing signals -A return to portable shellcode[END_REF]

can launch a malicious code execution with a single gadget. To date, such an attack defeats any heuristic engine.

Table 1 .

 1 3 exposes various software diversity techniques explored in the state-of-the-art. Background diversification, the gadgets within a program remain the same from one morph to another, however, their in-memory position is shifted by random offset. In contrast, gadgets do not survive fine-grained software diversification. Table1.3 also displays various diversification techniques.

			Table 1.3: Software diversity policies
	Name	Protection	Diversification technique	Implem.	Modularity Deterministic	Costs
				Soft Hard	Exec	Size
	ASLR	CG	random offset		N/A	0%
	Full-ASLR (PIE)	CG	random offset		14% [108]	N/A
	[105]	CG	random NOPs		<40%	<80%
	ASLP [108]	FG	sections, functions, BB, data		<1%	<80%
	ILR [109]	FG	instructions		13%-16% 14MB-264MB
	STIR [109]	FG	BBs, instructions		1.6%	73%
	SOFIA [112]	FG	cipher		106%	N/A

Software diversity aims to create several morphs of a program to harden stable exploit development. Table

1

.3 considers a software diversification coarse-grained when the protection relies on random-offsets introduced in the program code. Conversely, fine-grained software diversification implies complete randomization of code from a morph to another while preserving the semantic of the program. For instance, with coarse-grained software Chapter 1.

One can observe that software diversity is not deterministic. This is exactly the heart of the protection offered by software diversity. The general idea is to generate a random binary which in the presence of a vulnerability prevents exploit development based on Return-Oriented Programming techniques. While this type of protection raises the bar for exploit developers it remains incompatible with safety-critical embedded software guidelines

[START_REF] Rierson | A Practical Guide for Aviation Software and DO-178C Compliance[END_REF]

.

Table 1 .

 1 4 summarizes data-flow integrity defenses explored in the state-of-the-art. To remind, data-flow integrity prevents both control and non-control data corruption.Table 1.4

displays wether the studied protection defenses protect Code Pointer (CP), Data Pointer (DP), and/or regular Data (D). Other assessments in Table 1.4 such as Implementation, Modularity, Determinism, remain the same as in Table 1.1. According to Table 1.4, it seems that common data-flow integrity protections protect 1.4. State of the Art Synthesis

Table 1 .

 1 4: Data-flow integrity policies

	Name	Type	Protection	Implem.	Modularity Deterministic	Costs
			CP DP D Soft Hard	Exec	Size
	CCFI [113]	Crypto			23%	N/A
	PointGuard [114]	Crypto			0-20%	N/A
	DSR [115]	Crypto			15-28%	N/A
	PAC [118]	Crypto			0.5%	N/A
	Softbound [123]	Fat Pointers			<79%	N/A
	Hardbound [124]	Fat Pointers			<15%	N/A
	Intel MPX [120]	Fat Pointers			<150% <0.5%
	Shakti-T [125]	Fat Pointers			N/A	N/A
	CPI/CPS [127]	Pointer Isolation			10%	N/A
	DFI [129]	Tagged memory			43-104%	50%
	WIT [130]	Tagged memory			10-25%	12.5%
	HDFI [131]	Tagged memory			2%		<1%

CP: Code Pointers, DP: Data Pointer, D: Data, N/A: Not Available code pointers thus ensuring fine-grained control-flow integrity. In table

1

.4 there are also quite a few solutions that propose data pointers and even regular data protection

Table 3 .

 3 1: Modified Bergman's minimal model paramters

	Parameter Unit	Description
	G(t)	mg/dM	Blood Glucose concentration.
	X(t)	min -1	Effect of active insulin.
	I(t)	mU/L	Blood insulin concentration
	D(t)	mg/(dL.min) Meal disturbance function.
	U(t)	mU/min	Exogenous insulin.
	G b	mg/dL	Basal blood glucose concentration.
	I b	mU/L	Basal blood insulin concentration.
	V I	L	The volume of insulin distribution pool.
	p 1	min -1	Glucose clearance rate independent of insulin.
	p 2	min -1	Rate of clearance of active insulin.
	p 3	L/(min 2 .mU ) Increase in uptake ability caused by insulin.
	p 4	min -1

  .10.

	Pump Kernel	CGM	Mechanical
	Logic	Task	Injector Routine
	Request blood sugar
		Read blood sugar
	Return blood sugar mg/dL
	Evaluate
	blood sugar concentration
	Determine insulin to inject
	Insulin injection command
			Transfers insulin
			amount

Table 3

 3

.2 summarizes these variants.

The first variant in Table

3

.2, SecPump-BLE, is the implementation described in the previous section. It targets an off-the-shelf STM32 microcontroller and supports the Blue-3.3. SecPump

Table 3 .

 3 2: SecPump variants

	SecPump	Possible	Pump	O.S	Target	Lines of
	version	extension	communication	support	architecture	Code
	SecPump	Software	BLE/Serial	Bare-metal	STM32	18k
	BLE				ARM
	SecPump	Software	BLE/Serial	FreeRTOS	STM32	27k
	RT-BLE				ARM
	SecPump	Hardware	Serial	Bare-metal	Digilent Xilinx Arty-35T	7
	RISC-V	Software			RISC-V
	tooth Low Energy communication with a remote smartphone. This variant is flexible, it
	may be easily compiled without the manual mode. In other words, the Bluetooth Low
	Energy (BlueNRG) expansion module of the STM32 board is not indispensable to operate
	the pump. Of course, it removes wireless functionalities, but the latter can be replaced
	with serial communication.

Table 3 .

 3

			3: Comparison table
		openAPS	GIP	Open	SecPump	Commercial
			GIIP	Syringe		Pumps
	Open-source
	Price	$750+	-	<$100	$30 -$130	$260 -$5000
	Practicality					-
	Connectivity	Bluetooth	-	Ethernet	BLE	-
		Serial		Wifi
	Security-oriented

= Yes; = Partial; = No; -= Not defined Table

3

.3 compares the existing insulin/infusion pump platforms regarding five criteria.

Table 4 .

 4 1: TrustFlow Security Benchmark.

	Protection			Sensitive data
		function pointer	longjmp
	r e t u r n a d d r e s s b a s e p o i n t e r	s t a c k	h e a p	d a t a / b s s	s t a c k v a r i a b l e h e a p	d a t a / b s s	d a t a s t a c k s p i l l e d s t a c k d a t a d a t a d a t a / b s s
	B

  At execution-time, each function's stack should insert a Rand-Guard between vulnerable buffers and data variables. Although this protection is close to the regular stack canary, it needs a random number so that the value of the guard is different for each existing embedded application. Unfortunately, unlike desktop computers, most low-end microcontrollers don't have dedicated hardware support for Random Number Generation/Truly Random Number Generator

	Chapter 5. BackGuard
	and additional secure libraries that are linked to the final executable code. Overall, the
	BackGuard framework takes up the following implementation challenges:
	Backward-edge control-flow integrity: The BackGuard compiler that generates
	the backward-edge protection should be aware when a return address is spilled in the
	memory. Once this is the case, BackGuard needs to generate the appropriate code that
	identifies the return address in the bitmap. Finally, when a function returns using a
	previously spilled return address, BackGuard should also generate the return address
	verification code.
	Data Execution Prevention (DEP) and RO-Guards: During the boot sequence
	of the embedded application, an MPU should be configured such that DEP and code anti-
	tampering is enforced. Furthermore, the MPU needs to insert the RO-Guards to protect
	the bitmap, delimit the upper stack boundary, and the unsafe global variables memory
	space.
	Rand-Guards:
	To summarize, BackGuard hardens low-end applications by enforcing both backward-edge
	control-flow integrity thanks to a dedicated bitmap where each set bit refers to a valid
	pointer destination. BackGuard also clusters spatial vulnerabilities with Rand-Guards
	and RO-Guards.
	Such security features can only be implemented using a strong compiler infrastructure

Table 5 .

 5 1: MPU configurationThe boot sequence of the microcontroller also includes the generation of the Random-Guard value. BackGuard leverages the property of SRAM's initial values to generate a random number. As a disclaimer, the goal of this study is not to evaluate the randomness of microcontroller-based SRAM initial values. Several works in the literature address this topic and provide very relevant results

	Priority	Memory	Permissions
	1	Code	RX
	2	Data (stack, BSS, Data, unsafe-regions)	RW
	3	Stack-RO-Guard	R
	4	Date-RO-Guard	R
	5	Bitmap	RW
	6	MPU-Configuration	R
		R=Read; W=Write; X=Execute

Table 5 .

 5

		2: AIR measurements
		Best-case Worst-case
	BAIR	99.99%	99.98%
	AIR	83.33%	83.31%
	According to the measurements, the protection enforces the consistency of the control-
	flow graph to 99% for function returns. In turn, the overall AIR is much less accurate due to
	the lack of forward-edges protection. Although indirect forward-edges remain exploitable,
	they are considered as a low-security risk. Indirect function calls using pointers are less
	used in the context of embedded systems programming. Combined with the fact that
	BackGuard isolates function pointers from vulnerable buffers using random guards, the
	likelihood of working indirect function call exploits is possible but harder.
	Finally, using ROPgadget [94], 2261 return-oriented gadgets in the whole SecPump
	application are found. After applying the bitmap protection, we measured that in the
	worst-case only 14 gadgets were usable at the same time (99.4% gadget reduction).
	Qualitative Analysis: To improve the quantitative security analysis, we propose

a qualitative analysis of the protection by describing the exploit development workflow to thwart BackGuard. To validate this workflow, The security exploits exposed in section 3.4.1 are re-used and readapted.

Figure 5.8 displays the development steps of a functional exploit in the presence of Chapter 5. BackGuard BackGuard.

  is an ARM instrumentation-based framework that protects real-time embedded systems against memory safety issues. RECFISH instruments pre-compiled minimal real-time embedded systems to enforce control-flow integrity. It protects function backward-edges thanks to an RTOS-MPU protected shadow stack and indirect forwardedges thanks to immutable labels. While the backward-edge security policy of both REC-FISH and BackGuard is broadly the same, BackGuard protects sensitive function pointers with Random-Guard, RECFISH enforces control-flow graph coherency with labels. Thus, RECFISH can be vulnerable to control-flow bending attacks[START_REF] Carlini | Control-flow bending: On the effectiveness of control-flow integrity[END_REF] while BackGuard can be defeated by memory disclosures. Regarding the execution-time overhead, RECFISH induces 30% execution-time overhead on CoreMark 1000 while BackGuard induces 6.8% to 23.4% depending on the variant. In terms of flexibility, RECFISH applies to pre-

compiled ARM binaries. This approach is better in security that BackGuard. It allows instrumenting pre-compiled/closed-source libraries. Unfortunately, binary patching is not always compatible with software-engineering aspects. BackGuard provides a compileroriented approach compatible with full modularity, portability, and compatibility with software tests. Besides, BackGuard operates on the LLVM-IR making it more flexible than RECFISH.

µArmor

[START_REF] Abbasi | Challenges in designing exploit mitigations for deeply embedded systems[END_REF]

is a Clang/LLVM compiler-based memory safety protection for ARM bare-metal embedded systems. µArmor enforces three protections to mitigate memorybased exploits: µESP, µSSP, and µScramble. µESP enforces non-executable permissions on non-code regions using the ARM MPU. µSSP is a stack smashing protection based on a random value generated by µRNG, an SRAM based PUF random number generator.

  5.6. Comparison with related work overhead which is better than BackGuard.Silhouette[START_REF] Zhou | Silhouette: Efficient Protected Shadow Stacks on Embedded Systems[END_REF] is a memory isolation protection that efficiently protects ARM embedded systems against control-flow hijacking attacks. Silhouette is based on the LLVM compiler and introduces native code generative passes to enforce memory safety. Silhouette protects backward-edges thanks to a protected shadow call stack. Besides, like RECFISH[START_REF] Walls | Control-flow integrity for real-time embedded systems[END_REF], Silhouette protects forward-edges thanks to immutable labels that force the application execution to comply with its control-flow graph. Finally, to protect the shadow stack Silhouette leverages the feature of the unprivileged STRT instructions of the ARM instruction set. Regardless of the processor execution mode, these specific instructions are treated as if they were executed in unprivileged mode. Thus, Silhouette leverage this feature to create two protection domains. On the one hand, the application is only using unprivileged stores and on the other hand privileged domain uses the regular ARM STR instructions. The silhouette's MPU is configured such that the shadow stack is readable and writeable in privileged mode but only readable in unprivileged mode. Hence it ensures that privileged code running using unprivileged instructions and unprivileged code cannot tamper the shadow stack. As a result, only code function prologue and epilogue uses regular STR instructions to write in the shadow stack. Silhouette provides better security protection than BackGuard. It ensures safe memory accesses thanks to the ARM STRT instruction feature. However, in its threat model silhouette does not protect the HAL library code. This code should be run at the highest privileges because it accesses the peripherals and the I/O. While this code is rendered unreachable from the applica-

	Chapter 5. BackGuard
	tion point of view, it may contain unprotected exploitable vulnerabilities that BackGuard
	considers. On average Silhouette induces less than 5% execution-time overhead and a
	geometric mean of 21.4% and 25.5% code size overhead on CoreMark-Pro and BEEBS.
	However, to maintain the STRT memory access feature, Silhouette relies on heavy modi-
	fication of the LLVM ARM backend. While it provides safer security than BackGuard its
	flexibility and portability are more impacted.
	EPOXY [167] is an LLVM compiler-based embedded system protection that mixes
	memory safety and least privilege execution. EPOXY extends the CPI and CPS project
	such that any embedded application maintains two concurrent stacks. One stack is dedi-
	cated to unsafe objects such as buffer, the other stack is dedicated to sensitive code and
	data pointers. EPOXY [162] clusters the unsafe stack with a guard to detect any over-
	flow attempt. At boot-time EPOXY also configure the ARM microcontroller to enforce
	DEP and code anti-tampering. EPOXY drops the privileges of the running application
	to prevent any malicious write to either modify the MPU configuration, sensitive IO, or
	peripherals. At compilation time EPOXY identifies which store instruction is allowed
	to write the sensitive IO/peripherals. Before each privileged store, EPOXY raises the
	application privileges such that the store can be performed. The privileges are dropped
	immediately after. EPOXY induces 1.6% execution-time overhead which is better than
	BackGuard. Unfortunately, as the other previous proposition, EPOXY is less flexible than
	BackGuard.

  Conclusionaccompanied by a set of diversification passes dedicated to embedded system applications. BackFlow has been published as "BackFlow: Backward Edge Control Flow Integrity Enforcement for low-End ARM Microcontrollers" at the IEEE DATE conference 2020. Also, the efficiency of BackFlow has been demonstrated as "BackFlow: Backward Edge Con-

	trol Flow Integrity Enforcement for low End-ARM Real-Time Systems" at the University
	Booth Demonstration at IEEE DATE 2020. Finally, the results regarding BackGuard, the
	improvement of BackFlow has not been published yet. A final BackGuard optimization
	not included in this thesis will be evaluated before publication to the ACM Transactions
	on Embedded Computing Systems journal upon submission of this manuscript to the
	reviewers.
	According to the assessments, BackGuard can ensure a reasonable backward-edge
	control-flow integrity protection with 5% execution-time overhead on average. The main
	backward-edge control-flow integrity protection provided by BackGuard relies on an up-
	dated bitmap where each set bit represents a valid control-flow destination. This backward-
	edge protection provides an accurate average indirect target reduction close to 99.99% and
	requires only 3.1% of the available microcontroller memory. Moreover, BackGuard hard-
	ens memory exploits development thanks to RO-Guards and Rand-Guards. These protec-
	tions prevent spatial memory exploits to reach sensitive microcontroller memory regions.
	Finally, BackGuard efficiently configures a Memory Protection Unit to enforce Data Exe-
	cution Prevention. At this time, BackGuard does not mitigate against information leakage
	and temporal memory safety.
	Final Note: BackGuard is originally an extension from BackFlow, a compiler-based

BackGuard

aims at keeping a sufficient trade-off between security, performance, and code-size overhead. Besides, unlike other existing works, BackGuard protection is flexible. Indeed, BackGuard extends the Clang/LLVM compiler infrastructure with external plugins that can be loaded within the compilation workflow without requiring any internal invasive compiler modification. As a result, BackGuard is simple to integrate into realworld embedded software development processes. Also, BackGuard is compatible with Clang/LLVM versions available from official repositories, it does not require any Clang/L-LVM recompilation from sources. Finally, the BackGuard plugins operate on the LLVM Intermediate Representation. This feature makes it multi-architecture compatible. memory safety protection for low-end ARM microcontrollers. Unlike BackGuard, Back-Flow was a compiler back-end extension specific to the ARM Instruction Set Architecture.

Two passes of BackFlow were dedicated to building dynamic bitmap protection, and another two passes were dedicated to building static bitmap protection. BackFlow was 5.7.

1

  Off-the-shelf medical devices . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2 Insulin pump closed-loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.1 C program memory layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.2 Spatial memory issue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.3 Temporal memory issue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.4 Control-flow graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 1.5 Stack-based buffer overflow issue . . . . . . . . . . . . . . . . . . . . . . . . 17 1.6 Stack-based buffer overflow exploit . . . . . . . . . . . . . . . . . . . . . . . 18 1.7 Common exploits mitigations . . . . . . . . . . . . . . . . . . . . . . . . . . 19 1.8 Control-flow diversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 1.9 Return-Oriented Programming attack . . . . . . . . . . . . . . . . . . . . . 22 1.10 Data-oriented attack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 1.11 Memory safety attacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 1.12 Control-flow integrity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 1.13 Label-based control-flow integrity . . . . . . . . . . . . . . . . . . . . . . . . 28 1.14 Shadow call stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 1.15 Branch monitoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 1.16 Indirect branch verification . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 1.17 ROP signature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 1.18 Software diversification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 1.19 Fat Pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 1.20 Sensitive data memory separation . . . . . . . . . . . . . . . . . . . . . . . . 51 1.21 Tagged sensitive data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 2.1 Generative approaches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 3.1 Open-Syringe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 3.2 OpenAPS closed-loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 3.3 SecPump . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 3.4 Open-loop regulation system . . . . . . . . . . . . . . . . . . . . . . . . . . 82 3.5 SecPump manual injection sequence . . . . . . . . . . . . . . . . . . . . . . 83 3.6 Manual mode initial state . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 3.7 Manual mode step insulin injection . . . . . . . . . . . . . . . . . . . . . . . 86 3.8 Manual mode meal perturbation simulation . . . . . . . . . . . . . . . . . . 86 3.9 Closed-loop regulation system . . . . . . . . . . . . . . . . . . . . . . . . . . 87 3.10 SecPump automatic injection sequence . . . . . . . . . . . . . . . . . . . . . 87 3.11 PID blood glucose regulation . . . . . . . . . . . . . . . . . . . . . . . . . . 88 3.12 Remote code execution in SecPump . . . . . . . . . . . . . . . . . . . . . . 91 4.1 TrustFlow top-down approach . . . . . . . . . . . . . . . . . . . . . . . . . . 103

•

  Commit & Lookup: This state is reached when two custom instructions follow each other in the pipeline. In such case TrustFlow performs both a Commit and a Lookup operation. This state is reached when two custom instructions follow each other in the pipeline. In such case TrustFlow performs enables a Check and a

	A.3. Data restoration
	Lookup operation.
	XXIV

• Check & Lookup:

0(x2) add x2, x1, x3 nop add x2, x1, x3

	Time (in clock cycle)
	CC1	CC2	CC3		CC4		CC5		CC6
	IF lws x1, IF ID EX IF/ID ID/EX IF ID IF/ID	EX/MEM ID/EX IF/ID	MEM ID	MEM/WB EX/MEM ID/EX	WB EX Data forwarding	MEM/WB EX/MEM	MEM	MEM/WB	WB

Table C .

 C 1: ARM Core Registers

Purpose in the procedure call standard Register Special

	Program counter	R15	PC
	Link Register	R14	LR
	Stack Pointer	R13	SP
	Variable Registers	R4-R7
	Scratch Registers	R0-R3

  .1.

		_write:
		push {r4, r6, r7, lr}
	_write:	mov r4, lr
	push {r4, r6, r7, lr}	bl <__bitmap_reg__>
	add r7, sp, #8	add r7, sp, #8
	subs r0, #1	subs r0, #1
	cmp r0, #1	cmp r0, #1
	... assembly code	... assembly code
	cmp r0, #0	cmp r0, #0
	it ne	it ne
	movne r4, #0	movne r4, #0
	mov r0, r4	mov r0, r4
	pop {r4, r6, r7, pc}	ldr r4, [sp, #12]
	Non-protected function	bl <__bitmap_chk__> pop {r4, r6, r7, pc}
		Protected function

1.3. Existing Defenses

4.3. Implementation is displayed. Another "feature" algorithm implemented in the static analyzer prints the longest path for the developer. This critical path can then be optimized to reduce the trusted TLB footprint of its application.

Acknowledgements

Acknowledgements

The existence of this work would probably require the writing of a second manuscript to thank all the people who supported it. It is thanks to them, over a time span of three amazing years, that I could complete this work.

First of all, I would like to thank my thesis' jury: Mr. Giogio Di Natale, Mrs. Marie-

Code Emission

Intermediate Representa on

Code in SSA form.

Intermediate Representa on

Code in SSA form.

Instruc on Scheduling

Chapter 3. SecPump ware injection) and hardware attacks (e.g., side channel, glitch attacks) can be triggered on the pump. On the blue-team side, SecPump can be extended to accommodate novel countermeasures by considering determinism, safety, and real-time aspects.

Initially, this chapter reviews the open-existing platforms that inspired the design of SecPump. Section 3.3 exhibits the wireless insulin pump model, its software architecture, and the various algorithms that govern the functioning of the device. To showcase that SecPump is a suitable target for security assessments, section 3.4 displays various security attacks performed on the wireless pump. Finally, the last section is dedicated to the open-source assets of the platform regarding the related work. It shows how SecPump complements the existing platforms.

TrustFlow

Summary of the Chapter

This Chapter introduces TrustFlow, the first approach of this thesis. TrustFlow is a novel hardware/software co-designed framework that provides efficient finegrained control-flow integrity protection for critical embedded systems. Trust-Flow is composed of an LLVM-based compiler toolchain that generates a secure code. The latter is then executed on an extended RISC-V processor that keeps track of sensitive data using a trusted memory. The obtained results show that the contribution is practical for developers, providing a high level of trust in life-critical embedded systems with an execution-time overhead of less than 1%. The backward-edge control-flow integrity is performed after the register allocation 5 BackGuard

Summary of the Chapter

This chapter introduces BackGuard, the second approach of this thesis. Back-Guard is a compiler-based toolchain that protects embedded system systems against memory-based attacks. More specifically, BackGuard is intended for tiny constrained embedded systems generally implemented in bare-metal. Unlike TrustFlow, BackGuard is only implemented at the software level. The latter does not require any specific invasive hardware support to protect embedded applications. BackGuard is implemented within the Clang/LLVM compiler and is tested in this chapter on the ARM ISA. The control flow integrity generated by the compiler relies on a bitmap, where each set bit indicates a valid pointer destination. The memory exploits protection is enhanced by in-memory guards that prevent spatial memory vulnerabilities to spread. The efficiency of the framework is benchmarked using an STM32 NUCLEO F446RE microcontroller that implements various well-known benchmark suites. The obtained results show that the control flow integrity solution incurs an execution-time overhead of 5% on average. Chapter 5. BackGuard

Evaluation

This section assesses BackGuard protection. The whole BackGuard compiler extensions represent around 900 lines of C++ code. The external libraries of BackGuard include the custom bootloader that configures the memory protection unit (MPU), the bitmap, and the random guard value. It represents around 500 lines of C.

While BackGuard operates at the LLVM-IR and thus is architecture-independent, the evaluation of the countermeasure is performed on an off-the-shelf STM32F446-RE board based on the ARM architecture. More precisely, the security is assessed using SecPump-BLE [START_REF] Bresch | SecPump: A Connected Open Source Infusion Pump for Security Research Purposes[END_REF] the STM32 security-oriented system presented in Chapter 3. Both quantitative and qualitative security assessments are performed on the pump. This evaluation reveals the average target reduction of BackGuard, the gadget reduction, and finally, the exploit development steps required by an attacker to bypass BackGuard.

While the size overhead of BackGuard is measured on the pump application, the execution-time overhead of the protection is measured with well-known benchmark suites dedicated to low-end ARM microcontrollers such as CoreMark [START_REF] Gal-On | Exploring CoreMark™ -A Benchmark Maximizing Simplicity and Efficacy[END_REF], Dhrystone [START_REF] Weicker | Dhrystone: A synthetic systems programming benchmark[END_REF], and BEEBS [START_REF] Pallister | BEEBS: Open Benchmarks for Energy Measurements on Embedded Platforms[END_REF]. Also, we implemented a backend variant of BackGuard and a shadowstack variant of BackGuard to compare them with the IR variant detailed along with this Chapter. In the end, BackGuard is a compiler security framework offering several protection variants from middle-end to the backend. Finally, this section demonstrates that an acceptable level of security can be achieved on low-end microcontrollers with very few constraints and modifications in the development toolchains commonly used by embedded system developers.

Security evaluation

As previously explained, SecPump [START_REF] Bresch | SecPump: A Connected Open Source Infusion Pump for Security Research Purposes[END_REF] is used to assess the security protection induced by BackGuard. SecPump is a functional wireless infusion pump system workbench tailored to security evaluation. The cyber-physical model targets on an off-the-shelf STM32 with a Bluetooth Low Energy extension board. It is highly representative of the next generation of IoT devices. One of the main advantages of the platform is that it models the classical closed-loop regulation of the glucose-insulin thanks to an integrated PID.

Quantitative Analysis:

The entire embedded application consists of 18312 lines of C (including the external libraries). To evaluate the control-flow integrity accuracy provided by the BackGuard's bitmap, the Average Indirect target Reduction [START_REF] Zhang | Control flow integrity for cots binaries[END_REF] (AIR) is measured on the secured application. To remind from Chapter 1, section 1.3.1, the AIR [START_REF] Zhang | Control flow integrity for cots binaries[END_REF], gives a percentage of how much a protection enhances compliance of an application to its controlflow graph. The AIR is given by Formula 5.1.

N is the number of indirect control-flow transfers in a program, S the total number of target addresses that can be reached by a branch (it is the size of the binary). T j executed in order by the back-end, the prologue and epilogue code insertion happens after the register allocation pass. Indeed, to determine the registers that should be spilled in a stack frame, the prologue and epilogue code insertion pass should be aware of the registers used by a callee. Thus, the prologue and epilogue inserter pass is a machine function pass that operates at the function level. The insertion of the prologue and epilogue mostly involves stack unwinding, finalizing the function layout, saving the callee-saved registers, and then emitting the prologue and epilogue code. The prologue and epilogue insertion pass is located in the target-dependent code generator of the back-end. More specifically, the "PrologEpiloginserter.cpp" file is responsible for handling the Prologue and Epilogue Insertion (PEI). PEI operates on "Machine Functions". As displayed in Figure B.1, it calls the "SpillCalleeSavedRegs" function that determines which registers in the callee should be saved. It also assigns a stack slot for any XXVII Annex B. Annexe 2 : RISC-V prologue and epilogue insertion called registers. Finally, the function that inserts the code for the callee-saved registers used in a function is achieved by "insertCSRSaves". This specific function either call the "spillCalleeSavedRegisters" function (if implemented in the back-end) or the "storeReg-ToStackSlot" to spill the caller registers. The "storeRegToStackSlot" is a regular function that is usually used in various passes of the back-end to insert load and/or store instruction to spill a register in a stack frame. This function is not specifically dedicated to the PEI.

List of Tables

Figure B.2: LLVM PEI pass

The version of LLVM used during the thesis was still a testing version not pushed on the official stream. At that time, the RISC-V back-end used the current "storeReg-ToStackSlot" function to store spilled registers in a stack frame and "loadRegFromStack-Slot" to restore the spilled registers from the memory. One strategy would have been to modify this function so that it uses custom instructions to secure the memory loads. Unfortunately, this function is not only used by the prologue and epilogue inserted in the back-end. Modifying it could induce hazards in code generation. For this reason, we extended the RISC-V backend so that it uses the predefined "spillCalleeSavedRegisters" and "restoreCalleeSavedRegisters" functions. These two functions are only used for prologue and epilogue generation and, depending on the security level (explained in section 4.6), secure the spilled registers with custom instructions.