├── LICENSE ├── README.md ├── drama ├── Makefile ├── README.md ├── hugepage.sh └── src │ ├── include │ ├── rev-mc.h │ └── utils.h │ ├── main.c │ ├── rev-mc.c │ └── utils.c ├── hammersuite ├── .gitignore ├── Makefile ├── README.md ├── hugepage.sh ├── performance.sh └── src │ ├── addr-mapper.c │ ├── allocator.c │ ├── dram-address.c │ ├── hammer-suite.c │ ├── include │ ├── addr-mapper.h │ ├── allocator.h │ ├── dram-address.h │ ├── hammer-suite.h │ ├── memory.h │ ├── params.h │ ├── types.h │ └── utils.h │ ├── main.c │ ├── memory.c │ ├── params.c │ └── utils.c └── py ├── hammerstats.py ├── hammertime ├── __init__.py ├── _native.c ├── _native.so ├── dramtrans.py ├── fliptable.py └── sim.py └── histogram.py /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 | # TRRespass 2 | 3 | This is the repository for the TRRespass Rowhammer fuzzer. Recent DDR4 chips include on-chip TRR mitigations that stop bit flips using standard Rowhammer access patterns such as double-sided, single sided or one-location hammering. TRRespass automatically discovers novel Many-sided Rowhammer variants that can bypass these mitigations and trigger bit flips on the recent systems with DDR4 memory. TRRespass requires the DRAM address mapping functions to work effectively. 4 | 5 | Additional information about TRRespass can be found here: https://www.vusec.net/projects/trrespass/ 6 | 7 | The paper that describes more details appears at IEEE Security and Privacy 2020 and can be found here: https://download.vusec.net/papers/trrespass_sp20.pdf 8 | 9 | ### ./drama 10 | 11 | Inside the `drama` folder you can find a tool that helps you reverse engineer the DRAM memory mappings used by the memory controller. 12 | Read the README in the folder for more details 13 | 14 | ### ./hammersuite 15 | 16 | Inside the `hammersuite` folder you can find the fuzzer we used. 17 | Again, read the README in the folder for more details 18 | -------------------------------------------------------------------------------- /drama/Makefile: -------------------------------------------------------------------------------- 1 | SDIR=src 2 | IDIR=$(SDIR)/include 3 | LDIR=lib 4 | BUILD=obj 5 | ODIR=src/.obj 6 | 7 | CFLAGS=-I$(IDIR) #-ggdb 8 | # CXX=g++ 9 | LDFLAGS= 10 | 11 | OUT=tester 12 | 13 | LDEPS= 14 | 15 | GB_PAGE=/sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages 16 | HUGEPAGE=/mnt/huge 17 | 18 | all: $(OUT) 19 | .PHONY: clean 20 | 21 | 22 | SOURCES := $(wildcard $(SDIR)/*.c) 23 | OBJECTS := $(patsubst $(SDIR)/%.c, $(ODIR)/%.o, $(SOURCES)) 24 | 25 | 26 | $(ODIR)/%.o: $(SDIR)/%.c 27 | mkdir -p $(ODIR) 28 | $(CXX) -o $@ -c $< $(CFLAGS) $(LDFLAGS) $(LDEPS) 29 | 30 | 31 | $(OUT): $(OBJECTS) 32 | mkdir -p $(BUILD) 33 | $(CXX) -o $(BUILD)/$@ $^ $(CFLAGS) $(LDFLAGS) $(LDEPS) 34 | chmod +x $(BUILD)/$@ 35 | 36 | clean: 37 | rm -rf $(BUILD) 38 | rm -rf $(ODIR) 39 | 40 | setup: 41 | echo "Mounting hugetlbfs" 42 | echo 1 | sudo tee -a $(GB_PAGE) 43 | @if ! [ -d $(HUGEPAGE) ]; then\ 44 | sudo mkdir $(HUGEPAGE);\ 45 | sudo mount -t hugetlbfs -o pagesize=1G none $(HUGEPAGE);\ 46 | sudo chown pit:pit $(HUGEPAGE);\ 47 | fi 48 | 49 | 50 | teardown: 51 | @if [ -d $(HUGEPAGE) ]; then\ 52 | sudo umount -f $(HUGEPAGE);\ 53 | sudo rm -r $(HUGEPAGE);\ 54 | fi 55 | echo 0 | sudo tee -a $(GB_PAGE) 56 | 57 | run: 58 | sudo $(BUILD)/$(OUT) 59 | -------------------------------------------------------------------------------- /drama/README.md: -------------------------------------------------------------------------------- 1 | # DRAMA 2 | 3 | This tool can be used to reverse engineer the DRAM mapping functions of the test system. 4 | It carries out two main tasks: 5 | 6 | - Recovering the bank conflicts functions 7 | - Recovering the row address function 8 | 9 | The tool is a bit hackish since it makes some strong assumptions on the bits used for different purposes. 10 | For instance it assumes that the bits from the physical address used to select the row are among the high bits. 11 | This seems to be a valid assumption on all the Intel consumer platforms we tested. 12 | However on server platforms and AMD ryzen machines it doesn't yield great results. 13 | Once recovered the functions these can be used in `hammersuite` as explained in the the other README. 14 | 15 | ## Usage 16 | 17 | ``` 18 | ./test [-h] [-s sets] [-r rounds] [-t threshold] [-o o_file] [-v] [--mem mem_size] 19 | -h = this help message 20 | -s sets = number of expected sets (default: 32) 21 | -r rounds = number of rounds per tuple (default: 1000) 22 | -t threshold = time threshold for conflicts (default: 340) 23 | -o o_file = output file for mem profiling (default: access.csv) 24 | --mem mem_size = allocation size (default: 5368709120) 25 | -v = verbose 26 | ``` 27 | 28 | We recommend running it as verbose (`-v`) to get more insights on what's going on. 29 | Otherwise it will simply output to stdout first the bank conflicts functions and then the row address mask. 30 | 31 | **Number of sets:** 32 | 33 | - The number of expected sets is defined by the memory configuration. For instance in a common dual-rank, single-channel configuration you would expect 32 banks (i.e., sets) in total. You can pass any value you want to the script. If this value is unknown 16 is usually a safe bet. 34 | 35 | **Time threshold:** 36 | 37 | - You can identify the time threshold by running the tool the first time with `-o` and plotting the results with the histogram.py script available in the repo. Once you know the threshold you can dinamycally pass it to the binary. 38 | -------------------------------------------------------------------------------- /drama/hugepage.sh: -------------------------------------------------------------------------------- 1 | gbFile="/sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages" 2 | 3 | mkdir /mnt/huge 4 | mount -t hugetlbfs -o pagesize=1G none /mnt/huge 5 | su -c 'echo 1 >'$gbFile 6 | cat $gbFile 7 | -------------------------------------------------------------------------------- /drama/src/include/rev-mc.h: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | #include "unistd.h" 3 | 4 | 5 | typedef struct { 6 | char* v_addr; 7 | uint64_t p_addr; 8 | } addr_tuple; 9 | 10 | //---------------------------------------------------------- 11 | // Functions 12 | 13 | 14 | void rev_mc(size_t sets_cnt, size_t threshold, size_t rounds, size_t m_size, char* o_file, uint64_t flags); 15 | -------------------------------------------------------------------------------- /drama/src/include/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | #define BIT(x) (1ULL<<(x)) 8 | #define KB(x) ((x)<<10ULL) 9 | #define MB(x) ((x)<<20ULL) 10 | #define GB(x) ((x)<<30ULL) 11 | #define CL_SHIFT 6 12 | #define CL_SIZE 64 13 | 14 | 15 | #define F_CLEAR 0L 16 | #define F_VERBOSE BIT(0) 17 | #define F_EXPORT BIT(1) 18 | 19 | #define MEM_SHIFT (30L) 20 | #define MEM_MASK 0b11111ULL << MEM_SHIFT 21 | #define F_ALLOC_HUGE BIT(MEM_SHIFT) 22 | #define F_ALLOC_HUGE_1G F_ALLOC_HUGE | BIT(MEM_SHIFT+1) 23 | #define F_ALLOC_HUGE_2M F_ALLOC_HUGE | BIT(MEM_SHIFT+2) 24 | #define F_POPULATE BIT(MEM_SHIFT+3) 25 | 26 | 27 | 28 | //---------------------------------------------------------- 29 | // Static functions 30 | 31 | static inline __attribute__((always_inline)) void clflush(volatile void *p) 32 | { 33 | asm volatile("clflush (%0)\n" 34 | :: "r" (p) : "memory"); 35 | } 36 | 37 | 38 | static inline __attribute__((always_inline)) void mfence() 39 | { 40 | asm volatile ("mfence" : : : "memory"); 41 | } 42 | 43 | 44 | static inline __attribute__((always_inline)) void lfence() 45 | { 46 | asm volatile ("lfence" : : : "memory"); 47 | } 48 | 49 | 50 | static inline __attribute__((always_inline)) uint64_t rdtscp(void) 51 | { 52 | uint64_t lo, hi; 53 | asm volatile("rdtscp\n" 54 | : "=a" (lo), "=d" (hi) 55 | :: "%rcx"); 56 | return (hi << 32) | lo; 57 | } 58 | 59 | 60 | static inline __attribute__((always_inline)) uint64_t rdtsc(void) 61 | { 62 | uint64_t lo, hi; 63 | asm volatile("rdtsc\n" 64 | : "=a" (lo), "=d" (hi) 65 | :: "%rcx"); 66 | return (hi << 32) | lo; 67 | } 68 | 69 | 70 | //---------------------------------------------------------- 71 | // Memory alloc 72 | 73 | 74 | typedef struct { 75 | char* buffer; 76 | uint64_t size; 77 | uint64_t flags; 78 | } mem_buff_t; 79 | 80 | 81 | int alloc_buffer(mem_buff_t* mem); 82 | 83 | int free_buffer(mem_buff_t* mem); 84 | 85 | 86 | //---------------------------------------------------------- 87 | // Helpers 88 | int gt(const void * a, const void * b); 89 | 90 | double mean(uint64_t* vals, size_t size); 91 | 92 | uint64_t median(uint64_t* vals, size_t size); 93 | 94 | char* bit_string(uint64_t val); 95 | 96 | -------------------------------------------------------------------------------- /drama/src/main.c: -------------------------------------------------------------------------------- 1 | 2 | #include "stdio.h" 3 | // #include /* for rdtsc, rdtscp, clflush */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "utils.h" 18 | #include "rev-mc.h" 19 | 20 | 21 | #define SETS_std (2*16) // 1rk-1ch 22 | #define ROUNDS_std 1000 23 | #define THRESHOLD_std 340 24 | #define MEM_SIZE_std GB(5L) 25 | #define O_FILE_std "access.csv" 26 | 27 | 28 | #define FIELDS "base,probe,rounds,time" 29 | 30 | 31 | //----------------------------------------------- 32 | // GLOBALS 33 | 34 | 35 | 36 | //----------------------------------------------- 37 | void print_usage() { 38 | fprintf(stderr, "[ LOG ] - Usage ./test [-h] [-s sets] [-r rounds] [-t threshold] [-o o_file] [-v] [--mem mem_size]\n"); 39 | fprintf(stderr, " -h = this help message\n"); 40 | fprintf(stderr, " -s sets = number of expected sets (default: %d)\n", SETS_std); 41 | fprintf(stderr, " -r rounds = number of rounds per tuple (default: %d)\n", ROUNDS_std); 42 | fprintf(stderr, " -t threshold = time threshold for conflicts (default: %d)\n", THRESHOLD_std); 43 | fprintf(stderr, " -o o_file = output file for mem profiling (default: %s)\n", O_FILE_std); 44 | fprintf(stderr, " --mem mem_size = allocation size (default: %ld)\n", (uint64_t) MEM_SIZE_std); 45 | fprintf(stderr, " -v = verbose\n\n"); 46 | } 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | //----------------------------------------------- 58 | int main(int argc, char** argv) { 59 | 60 | uint64_t flags = 0ULL; 61 | size_t sets_cnt = SETS_std; 62 | size_t rounds = ROUNDS_std; 63 | size_t m_size = MEM_SIZE_std; 64 | size_t threshold = THRESHOLD_std; 65 | char* o_file = (char*) O_FILE_std; 66 | 67 | flags |= F_POPULATE; 68 | 69 | if(geteuid() != 0) { 70 | fprintf(stderr, "[ERROR] - You need to run as root to access pagemap!\n"); 71 | exit(1); 72 | } 73 | 74 | while (1) { 75 | int this_option_optind = optind ? optind : 1; 76 | int option_index = 0; 77 | static struct option long_options[] = 78 | { 79 | /* These options set a flag. */ 80 | {"mem", required_argument, 0, 0}, 81 | {0, 0, 0, 0} 82 | }; 83 | int arg = getopt_long (argc, argv, "o:s:r:t:hv", 84 | long_options, &option_index); 85 | 86 | if (arg == -1) 87 | break; 88 | 89 | switch(arg) { 90 | case 0: 91 | switch (option_index){ 92 | case 0: 93 | m_size = atoi(optarg); // TODO proper parsing of this 94 | break; 95 | default: 96 | break; 97 | } 98 | break; 99 | case 'o': 100 | o_file = (char*) malloc(sizeof(char)*strlen(optarg)); 101 | strncpy(o_file, optarg, strlen(optarg)); 102 | flags |= F_EXPORT; 103 | break; 104 | case 's': 105 | sets_cnt = atoi(optarg); 106 | break; 107 | case 'r': 108 | rounds = atoi(optarg); 109 | break; 110 | case 't': 111 | threshold = atoi(optarg); 112 | break; 113 | case 'v': 114 | flags |= F_VERBOSE; 115 | break; 116 | case 'h': 117 | default: 118 | print_usage(); 119 | return 0; 120 | 121 | } 122 | } 123 | 124 | 125 | 126 | rev_mc(sets_cnt, threshold, rounds, m_size, o_file, flags); 127 | return 0; 128 | 129 | } 130 | 131 | 132 | 133 | 134 | /*I'm refactoring the set struct to add also timing in there. */ 135 | -------------------------------------------------------------------------------- /drama/src/rev-mc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "rev-mc.h" 19 | 20 | #define BOOL_XOR(a,b) ((a) != (b)) 21 | #define O_HEADER "base,probe,time\n" 22 | #define ALIGN_TO(X, Y) ((X) & (~((1LL<<(Y))-1LL))) // Mask out the lower Y bits 23 | #define LS_BITMASK(X) ((1LL<<(X))-1LL) // Mask only the lower X bits 24 | 25 | #define SET_SIZE 40 // elements per set 26 | #define VALID_THRESH 0.75f 27 | #define SET_THRESH 0.95f 28 | #define BITSET_SIZE 256 // bitset used to exploit bitwise operations 29 | #define ROW_SET_CNT 5 30 | 31 | // from https://stackoverflow.com/questions/1644868/define-macro-for-debug-printing-in-c 32 | #define verbose_printerr(fmt, ...) \ 33 | do { if (flags & F_VERBOSE) { fprintf(stderr, fmt, ##__VA_ARGS__); } } while(0) 34 | 35 | 36 | 37 | typedef std::vector set_t; 38 | 39 | //------------------------------------------- 40 | bool is_in(char* val, std::vector arr); 41 | bool found_enough(std::vector sets, uint64_t set_cnt, size_t set_size); 42 | void filter_sets(std::vector& sets, size_t set_size); 43 | void print_sets(std::vector sets); 44 | void verify_sets(std::vector& sets, uint64_t threshold, size_t rounds); 45 | 46 | //------------------------------------------- 47 | uint64_t time_tuple(volatile char* a1, volatile char* a2, size_t rounds) { 48 | 49 | uint64_t* time_vals = (uint64_t*) calloc(rounds, sizeof(uint64_t)); 50 | uint64_t t0; 51 | sched_yield(); 52 | for (size_t i = 0; i < rounds; i++) { 53 | mfence(); 54 | t0 = rdtscp(); 55 | *a1; 56 | *a2; 57 | time_vals[i] = rdtscp() - t0; 58 | lfence(); 59 | clflush(a1); 60 | clflush(a2); 61 | 62 | } 63 | 64 | uint64_t mdn = median(time_vals, rounds); 65 | free(time_vals); 66 | return mdn; 67 | } 68 | 69 | 70 | 71 | //---------------------------------------------------------- 72 | char* get_rnd_addr(char* base, size_t m_size, size_t align) { 73 | return (char*) ALIGN_TO((uint64_t) base, (uint64_t) align) + ALIGN_TO(rand() % m_size, (uint64_t) align); 74 | } 75 | 76 | 77 | 78 | //---------------------------------------------------------- 79 | uint64_t get_pfn(uint64_t entry) { 80 | return ((entry) & 0x3fffffffffffff); 81 | } 82 | 83 | //---------------------------------------------------------- 84 | uint64_t get_phys_addr(uint64_t v_addr) 85 | { 86 | uint64_t entry; 87 | uint64_t offset = (v_addr/4096) * sizeof(entry); 88 | uint64_t pfn; 89 | int fd = open("/proc/self/pagemap", O_RDONLY); 90 | assert(fd >= 0); 91 | int bytes_read = pread(fd, &entry, sizeof(entry), offset); 92 | close(fd); 93 | assert(bytes_read == 8); 94 | assert(entry & (1ULL << 63)); 95 | pfn = get_pfn(entry); 96 | assert(pfn != 0); 97 | return (pfn*4096) | (v_addr & 4095); 98 | } 99 | 100 | 101 | //---------------------------------------------------------- 102 | addr_tuple gen_addr_tuple(char* v_addr) { 103 | return (addr_tuple) { v_addr, get_phys_addr((uint64_t) v_addr)}; 104 | } 105 | 106 | 107 | 108 | 109 | //---------------------------------------------------------- 110 | // https://www.cs.umd.edu/~gasarch/TOPICS/factoring/fastgauss.pdf 111 | // gaussian elimination in GF2 112 | 113 | std::vector reduce_masks(std::vector masks) { 114 | 115 | size_t height, width, height_t, width_t; 116 | 117 | height = masks.size(); 118 | width = 0; 119 | for (auto m:masks) { 120 | uint64_t max_one = 64 - __builtin_clzl(m); 121 | width = (max_one > width)? max_one:width; 122 | } 123 | 124 | height_t = width; 125 | width_t = height; 126 | 127 | std::vector> mtx(height, std::vector(width)); 128 | std::vector> mtx_t(height_t, std::vector(width_t)); 129 | std::vector filtered_masks; 130 | 131 | for (size_t i =0; i> (__builtin_ctzl(v) + 1)); 178 | } 179 | 180 | 181 | 182 | //---------------------------------------------------------- 183 | std::vector find_functions(std::vector sets, size_t max_fn_bits, size_t msb, uint64_t flags) { 184 | 185 | std::vector masks; 186 | verbose_printerr("~~~~~~~~~~ Candidate functions ~~~~~~~~~~\n"); 187 | 188 | for (size_t bits = 1L; bits <= max_fn_bits; bits++) { 189 | uint64_t fn_mask = ((1L<<(bits))-1); // avoid the first 6 bits since they are the cacheline bits 190 | uint64_t last_mask = (fn_mask<<(msb-bits)); 191 | fn_mask <<= CL_SHIFT; 192 | verbose_printerr("[ LOG ] - #Bits: %ld \n", bits); 193 | while (fn_mask != last_mask) { 194 | if (fn_mask & LS_BITMASK(6)){ 195 | fn_mask = next_bit_permutation(fn_mask); 196 | continue; 197 | } 198 | for (size_t idx = 0; idx find_set_bits(uint64_t val) { 232 | std::vector set_bits; 233 | for (int i = 0; i<64; i++) { 234 | if (!(val & (1ULL << i))) 235 | continue; 236 | 237 | set_bits.push_back(i); 238 | } 239 | return set_bits; 240 | } 241 | 242 | //---------------------------------------------------------- 243 | std::vector get_dram_fn(uint64_t addr, std::vector fn_masks) { 244 | std::vector addr_dram; 245 | for (auto fn:fn_masks) { 246 | addr_dram.push_back(__builtin_parityl( addr & fn)); 247 | } 248 | return addr_dram; 249 | } 250 | 251 | //---------------------------------------------------------- 252 | /* 253 | It currently finds some of the interesting bits for the row addressing. 254 | @TODO still need to figure out which bits are used for the row addressing and which 255 | are from the bank selection. This is currently done manually 256 | */ 257 | uint64_t find_row_mask(std::vector& sets, std::vector fn_masks, mem_buff_t mem, uint64_t threshold, uint64_t flags) { 258 | 259 | 260 | 261 | addr_tuple base_addr = gen_addr_tuple(get_rnd_addr(mem.buffer, mem.size, 0)); 262 | std::vector same_row_sets; 263 | 264 | verbose_printerr("~~~~~~~~~~ Looking for row bits ~~~~~~~~~~\n"); 265 | 266 | 267 | for (int i = 0; i < 2; i++) { 268 | verbose_printerr("[LOG] - Set #%d\n", i); 269 | addr_tuple base_addr = sets[i][0]; 270 | std::vector base_dram = get_dram_fn((uint64_t)base_addr.p_addr, fn_masks); 271 | same_row_sets.push_back({base_addr}); 272 | uint64_t cnt = 0; 273 | while (cnt < ROW_SET_CNT) { 274 | 275 | addr_tuple tmp = gen_addr_tuple(get_rnd_addr(mem.buffer, mem.size, 0)); 276 | if (get_dram_fn((uint64_t) tmp.p_addr, fn_masks) != base_dram) 277 | continue; 278 | 279 | uint64_t time = time_tuple((volatile char*)base_addr.v_addr, (volatile char*)tmp.v_addr, 1000); 280 | 281 | if (time > threshold) 282 | continue; 283 | 284 | 285 | verbose_printerr("[LOG] - %lx - %lx\t Time: %ld <== GOTCHA\n", base_addr.p_addr, tmp.p_addr, time); 286 | 287 | same_row_sets[i].push_back(tmp); 288 | cnt++; 289 | } 290 | } 291 | 292 | 293 | 294 | 295 | uint64_t row_mask = LS_BITMASK(16); // use 16 bits for the row 296 | uint64_t last_mask = (row_mask<<(40-16)); 297 | row_mask <<= CL_SHIFT; // skip the lowest 6 bits since they're used for CL addressing 298 | 299 | while (row_mask < last_mask) { 300 | if (row_mask & LS_BITMASK(CL_SHIFT)){ 301 | row_mask = next_bit_permutation(row_mask); 302 | continue; 303 | } 304 | 305 | for (auto addr_pool:same_row_sets) { 306 | addr_tuple base_addr = addr_pool[0]; 307 | for (int i = 1; i < addr_pool.size(); i++) { 308 | addr_tuple tmp = addr_pool[i]; 309 | if ((tmp.p_addr & row_mask) != (base_addr.p_addr & row_mask)) { 310 | goto next_mask; 311 | } 312 | } 313 | 314 | } 315 | 316 | break; 317 | 318 | next_mask: 319 | row_mask = next_bit_permutation(row_mask); 320 | } 321 | 322 | // super hackish way to recover the real row mask 323 | for (auto m:fn_masks) { 324 | uint64_t lsb = (1<<(__builtin_ctzl(m)+1)); 325 | if (lsb & row_mask) { 326 | row_mask ^= (1<<__builtin_ctzl(m)); 327 | } 328 | } 329 | verbose_printerr("[LOG] - Row mask: 0x%0lx \t\t bits: %s\n", row_mask, bit_string(row_mask)); 330 | printf("0x%lx\n", row_mask); 331 | 332 | } 333 | 334 | 335 | //---------------------------------------------------------- 336 | void rev_mc(size_t sets_cnt, size_t threshold, size_t rounds, size_t m_size, char* o_file, uint64_t flags) { 337 | 338 | time_t t; 339 | 340 | int o_fd = 0; 341 | int huge_fd = 0; 342 | std::vector sets; 343 | std::vector used_addr; 344 | std::vector fn_masks; 345 | 346 | srand((unsigned) time(&t)); 347 | 348 | if (flags & F_EXPORT) { 349 | if (o_file == NULL) { 350 | fprintf(stderr, "[ERROR] - Missing export file name\n"); 351 | exit(1); 352 | } 353 | if((o_fd = open(o_file, O_CREAT|O_RDWR)) == -1) { 354 | perror("[ERROR] - Unable to create export file"); 355 | exit(1); 356 | } 357 | dprintf(o_fd, O_HEADER); 358 | } 359 | 360 | mem_buff_t mem = { 361 | .buffer = NULL, 362 | .size = m_size, 363 | .flags = flags , 364 | }; 365 | 366 | alloc_buffer(&mem); 367 | 368 | 369 | while (!found_enough(sets, sets_cnt, SET_SIZE)) { 370 | char* rnd_addr = get_rnd_addr(mem.buffer, mem.size, CL_SHIFT); 371 | if (is_in(rnd_addr, used_addr)) 372 | continue; 373 | 374 | used_addr.push_back(rnd_addr); 375 | 376 | addr_tuple tp = gen_addr_tuple(rnd_addr); 377 | bool found_set = false; 378 | for (size_t idx = 0; idx < sets.size(); idx++) { 379 | uint64_t time = 0; 380 | addr_tuple tmp = sets[idx][0]; 381 | time = time_tuple((volatile char*) tmp.v_addr, (volatile char*)tp.v_addr, rounds); 382 | if (flags & F_EXPORT) { 383 | dprintf(o_fd, "%lx,%lx,%ld\n",(uint64_t) tp.v_addr, (uint64_t) tmp.v_addr,time); 384 | } 385 | if (time > threshold) { 386 | verbose_printerr("[LOG] - [%ld] Set: %03ld -\t %lx - %lx\t Time: %ld\n", used_addr.size(), idx, tp.p_addr, tmp.p_addr, time); 387 | sets[idx].push_back(tp); 388 | found_set = true; 389 | break; 390 | } 391 | } 392 | if (!found_set) { 393 | sets.push_back({tp}); 394 | verbose_printerr( "[LOG] - Set: %03ld -\t %p <== NEW!!\n", sets.size(), tp.v_addr); 395 | } 396 | 397 | } 398 | 399 | filter_sets(sets, SET_SIZE); 400 | 401 | #ifdef DEBUG_SETS 402 | fprintf(stderr, "[ LOG ] - Cleansing sets. This may take a while... stay put\n"); 403 | verify_sets(sets, threshold, rounds); 404 | fprintf(stderr, "[ LOG ] - Done\n"); 405 | #endif 406 | 407 | if (flags & F_VERBOSE) { 408 | print_sets(sets); 409 | } 410 | 411 | fn_masks = find_functions(sets, 6, 30, flags); 412 | uint64_t row_mask = find_row_mask(sets, fn_masks, mem, threshold, flags); 413 | 414 | free_buffer(&mem); 415 | } 416 | 417 | 418 | 419 | // Fin. 420 | 421 | //---------------------------------------------------------- 422 | // Helpers 423 | 424 | bool is_in(char* val, std::vector arr) { 425 | for (auto v: arr) { 426 | if (val == v) { 427 | return true; 428 | } 429 | } 430 | return false; 431 | } 432 | 433 | //---------------------------------------------------------- 434 | bool found_enough(std::vector sets, uint64_t set_cnt, size_t set_size) { 435 | 436 | size_t found_sets = 0; 437 | 438 | for (int i =0; i < sets.size(); i++) { 439 | set_t curr_set = sets[i]; 440 | if (curr_set.size() > set_size) { 441 | found_sets += 1; 442 | } 443 | } 444 | 445 | if (found_sets > set_cnt) { 446 | fprintf(stderr, "[ERROR] - Found too many sets. Is %ld the correct number of sets?\n", set_cnt); 447 | exit(1); 448 | } 449 | 450 | return (found_sets >= (set_cnt * SET_THRESH)) ? true : false; 451 | } 452 | 453 | 454 | void filter_sets(std::vector& sets, size_t set_size) { 455 | 456 | for (auto s = sets.begin(); s < sets.end(); s++) { 457 | if (s->size() < set_size) { 458 | sets.erase(s); 459 | s -= 1; 460 | } 461 | } 462 | } 463 | 464 | 465 | void print_sets(std::vector sets) { 466 | 467 | for (int idx = 0; idx < sets.size(); idx++) { 468 | fprintf(stderr, "[LOG] - Set: %d\tSize: %ld\n", idx, sets[idx].size()); 469 | for (auto tmp: sets[idx]) { 470 | fprintf(stderr, "\tv_addr:%p - p_addr:%p\n", tmp.v_addr, (void*) tmp.p_addr); 471 | } 472 | } 473 | } 474 | 475 | #ifdef DEBUG_SETS 476 | 477 | void verify_sets(std::vector& sets, uint64_t threshold, size_t rounds) { 478 | 479 | for (auto s: sets) { 480 | // test every address against all the addresses in the set 481 | for (auto tp_base = s.begin(); tp_base < s.end(); tp_base++) { 482 | uint64_t conflicts = 0; 483 | for (auto tp_probe = s.begin(); tp_probe < s.end(); tp_probe++) { 484 | if (tp_base == tp_probe) 485 | continue; 486 | 487 | uint64_t time = time_tuple((volatile char*) tp_base->v_addr,(volatile char*) tp_probe->v_addr, rounds); 488 | if (time>threshold){ 489 | conflicts += 1; 490 | } 491 | } 492 | if (!(conflicts > VALID_THRESH*s.size())) { 493 | fprintf(stderr, "[ LOG ] - Removing: %p\n", tp_base->v_addr); 494 | s.erase(tp_base--); // reset the iterator 495 | } 496 | } 497 | } 498 | } 499 | 500 | #endif 501 | 502 | -------------------------------------------------------------------------------- /drama/src/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "utils.h" 13 | 14 | 15 | //----------------------------------------------- 16 | // Memory alloc 17 | 18 | int alloc_buffer(mem_buff_t* mem) { 19 | if (mem->buffer != NULL) { 20 | fprintf(stderr, "[ERROR] - Memory already allocated\n"); 21 | } 22 | 23 | uint64_t alloc_flags = MAP_PRIVATE | MAP_POPULATE | MAP_ANONYMOUS; 24 | 25 | mem->buffer = (char*) mmap(NULL, mem->size, PROT_READ | PROT_WRITE, alloc_flags, -1, 0); 26 | if (mem->buffer == MAP_FAILED) { 27 | perror("[ERROR] - mmap() failed"); 28 | exit(1); 29 | } 30 | 31 | if (mem->flags & F_VERBOSE) { 32 | fprintf(stderr, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 33 | fprintf(stderr, "[ MEM ] - Buffer: %p\n", mem->buffer); 34 | fprintf(stderr, "[ MEM ] - Size: %ld\n", mem->size); 35 | fprintf(stderr, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 36 | } 37 | return 0; 38 | 39 | } 40 | 41 | 42 | 43 | int free_buffer(mem_buff_t* mem) { 44 | return munmap(mem->buffer, mem->size); 45 | } 46 | 47 | 48 | 49 | 50 | 51 | //----------------------------------------------- 52 | // Helpers 53 | 54 | double mean(uint64_t* vals, size_t size) { 55 | uint64_t avg = 0; 56 | for (size_t i = 0; i < size; i++) { 57 | avg += vals[i]; 58 | } 59 | return ((double)avg) / size; 60 | } 61 | 62 | int gt(const void * a, const void * b) { 63 | return ( *(int*)a - *(int*)b ); 64 | } 65 | 66 | uint64_t median(uint64_t* vals, size_t size) { 67 | qsort(vals, size, sizeof(uint64_t), gt); 68 | return ((size%2)==0) ? vals[size/2] : (vals[(size_t)size/2]+vals[((size_t)size/2+1)])/2; 69 | } 70 | 71 | 72 | char* bit_string(uint64_t val) { 73 | static char bit_str[256]; 74 | char itoa_str[8]; 75 | strcpy(bit_str, ""); 76 | for (int shift = 0; shift < 64; shift++) { 77 | if ((val >> shift) & 1) { 78 | if (strcmp(bit_str, "") != 0) { 79 | strcat(bit_str, "+ "); 80 | } 81 | sprintf(itoa_str, "%d ", shift); 82 | strcat(bit_str, itoa_str); 83 | } 84 | } 85 | 86 | return bit_str; 87 | } 88 | -------------------------------------------------------------------------------- /hammersuite/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | -------------------------------------------------------------------------------- /hammersuite/Makefile: -------------------------------------------------------------------------------- 1 | SDIR=src 2 | IDIR=$(SDIR)/include 3 | LDIR=lib 4 | BUILD=obj 5 | ODIR=src/.obj 6 | DATA_DIR=$(PWD)/data/ 7 | 8 | CFLAGS=-I$(IDIR) -msse4.2 -ggdb -DDATA_DIR=\"$(DATA_DIR)\" 9 | # CXX=g++ 10 | LDFLAGS= 11 | 12 | OUT=tester 13 | 14 | LDEPS= 15 | 16 | GB_PAGE=/sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages 17 | HUGEPAGE=/mnt/huge 18 | 19 | all: $(OUT) 20 | .PHONY: clean 21 | 22 | 23 | SOURCES := $(wildcard $(SDIR)/*.c) 24 | OBJECTS := $(patsubst $(SDIR)/%.c, $(ODIR)/%.o, $(SOURCES)) 25 | 26 | 27 | $(ODIR)/%.o: $(SDIR)/%.c 28 | mkdir -p $(ODIR) 29 | $(CXX) -o $@ -c $< $(CFLAGS) $(LDFLAGS) $(LDEPS) 30 | 31 | 32 | $(OUT): $(OBJECTS) 33 | mkdir -p $(BUILD) 34 | $(CXX) -o $(BUILD)/$@ $^ $(CFLAGS) $(LDFLAGS) $(LDEPS) 35 | chmod +x $(BUILD)/$@ 36 | 37 | clean: 38 | rm -rf $(BUILD) 39 | rm -rf $(ODIR) 40 | 41 | setup: 42 | echo "Mounting hugetlbfs" 43 | echo 2 | sudo tee -a $(GB_PAGE) 44 | @if ! [ -d $(HUGEPAGE) ]; then\ 45 | sudo mkdir $(HUGEPAGE);\ 46 | sudo mount -t hugetlbfs -o pagesize=1G none $(HUGEPAGE);\ 47 | sudo chown pit:pit $(HUGEPAGE);\ 48 | fi 49 | 50 | 51 | teardown: 52 | @if [ -d $(HUGEPAGE) ]; then\ 53 | sudo umount -f $(HUGEPAGE);\ 54 | sudo rm -r $(HUGEPAGE);\ 55 | fi 56 | echo 0 | sudo tee -a $(GB_PAGE) 57 | 58 | run: 59 | sudo $(BUILD)/$(OUT) 60 | -------------------------------------------------------------------------------- /hammersuite/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vusec/trrespass/7ea523a4149daf1f1c4d8b099c2b3584f973d086/hammersuite/README.md -------------------------------------------------------------------------------- /hammersuite/hugepage.sh: -------------------------------------------------------------------------------- 1 | gbFile="/sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages" 2 | 3 | mkdir /mnt/huge 4 | mount -t hugetlbfs -o pagesize=1G none /mnt/huge 5 | su -c 'echo 1 >'$gbFile 6 | cat $gbFile 7 | -------------------------------------------------------------------------------- /hammersuite/performance.sh: -------------------------------------------------------------------------------- 1 | if [ "$1" == "" ]; then 2 | echo "Expected argument (powersave/ performance)" 3 | exit 4 | fi 5 | 6 | max_proc=$(cat /proc/cpuinfo | grep processor | tail -n 1 | cut -d ":" -f 2) 7 | mode=$1 8 | 9 | echo Max proc: $max_proc 10 | echo Setting mode: $mode 11 | 12 | for i in $(seq 0 $max_proc) 13 | do 14 | echo $mode | sudo tee -a /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor > /dev/null 15 | echo cat /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor = $(cat /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor) 16 | done 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /hammersuite/src/addr-mapper.c: -------------------------------------------------------------------------------- 1 | #include "addr-mapper.h" 2 | #include "utils.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | static size_t g_rmap_len = 0; 9 | static size_t g_base_row = 0; 10 | static size_t g_bks = 0; 11 | static size_t g_rows = 0; 12 | 13 | RowMap get_row_map(ADDRMapper * mapper, DRAMAddr * d_addr) 14 | { 15 | size_t idx = 16 | (d_addr->row - g_base_row) * get_banks_cnt() + d_addr->bank; 17 | assert(idx < g_bks * g_rows); 18 | return mapper->row_maps[idx]; 19 | } 20 | 21 | DRAM_pte get_dram_pte(ADDRMapper * mapper, DRAMAddr * d_addr) 22 | { 23 | RowMap rmap = get_row_map(mapper, d_addr); 24 | return rmap.lst[(d_addr->col) >> 6]; 25 | } 26 | 27 | RowMap gen_row_map(DRAMAddr d_src, MemoryBuffer * mem) 28 | { 29 | RowMap rmap; 30 | DRAM_pte *dst = (DRAM_pte *) malloc(sizeof(DRAM_pte) * g_rmap_len); 31 | d_src.col = 0; 32 | 33 | for (size_t col = 0; col < g_rmap_len; col++, d_src.col += (1 << 6)) { 34 | dst[col].d_addr = d_src; 35 | dst[col].v_addr = phys_2_virt(dram_2_phys(d_src), mem); 36 | } 37 | rmap.lst = dst; 38 | rmap.len = g_rmap_len; 39 | return rmap; 40 | 41 | } 42 | 43 | size_t rmap_idx(size_t bk, size_t row) 44 | { 45 | return row * get_banks_cnt() + bk; 46 | } 47 | 48 | void init_addr_mapper(ADDRMapper * mapper, MemoryBuffer * mem, 49 | DRAMAddr * d_base, size_t h_rows) 50 | { 51 | mapper->row_maps = 52 | (RowMap *) malloc(sizeof(RowMap) * h_rows * get_banks_cnt()); 53 | mapper->base_row = d_base->row; 54 | g_base_row = d_base->row; 55 | g_bks = get_banks_cnt(); 56 | g_rows = h_rows; 57 | // set global rmap_len 58 | g_rmap_len = ROW_SIZE / CL_SIZE; 59 | 60 | // create ptes list for every 61 | DRAMAddr d_tmp = {.bank = 0,.row = 0,.col = 0 }; 62 | for (size_t bk = 0; bk < get_banks_cnt(); bk++) { 63 | d_tmp.bank = bk; 64 | for (size_t row = 0; row < h_rows; row++) { 65 | d_tmp.row = g_base_row + row; 66 | mapper->row_maps[rmap_idx(bk, row)] = 67 | gen_row_map(d_tmp, mem); 68 | } 69 | } 70 | } 71 | 72 | void tear_down_addr_mapper(ADDRMapper * mapper) 73 | { 74 | for (int i = 1; i < g_rows * g_bks; i++) { 75 | free(mapper->row_maps[i].lst); 76 | } 77 | free(mapper->row_maps); 78 | } 79 | -------------------------------------------------------------------------------- /hammersuite/src/allocator.c: -------------------------------------------------------------------------------- 1 | #include "allocator.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "utils.h" 15 | 16 | int alloc_buffer(MemoryBuffer * mem) 17 | { 18 | if (mem->buffer != NULL) { 19 | fprintf(stderr, "[ERROR] - Memory already allocated\n"); 20 | } 21 | 22 | if (mem->align < _SC_PAGE_SIZE) { 23 | mem->align = 0; 24 | } 25 | 26 | uint64_t alloc_size = mem->align ? mem->size + mem->align : mem->size; 27 | uint64_t alloc_flags = MAP_PRIVATE | MAP_POPULATE; 28 | 29 | if (mem->flags & F_ALLOC_HUGE) { 30 | if (mem->fd == 0) { 31 | fprintf(stderr, 32 | "[ERROR] - Missing file descriptor to allocate hugepage\n"); 33 | exit(1); 34 | } 35 | alloc_flags |= 36 | (mem->flags & F_ALLOC_HUGE_1G) ? MAP_ANONYMOUS | MAP_HUGETLB 37 | | (30 << MAP_HUGE_SHIFT) 38 | : (mem->flags & F_ALLOC_HUGE_2M) ? MAP_ANONYMOUS | 39 | MAP_HUGETLB | (21 << MAP_HUGE_SHIFT) 40 | : MAP_ANONYMOUS; 41 | } else { 42 | mem->fd = -1; 43 | alloc_flags |= MAP_ANONYMOUS; 44 | } 45 | mem->buffer = (char *)mmap(NULL, mem->size, PROT_READ | PROT_WRITE, 46 | alloc_flags, mem->fd, 0); 47 | if (mem->buffer == MAP_FAILED) { 48 | perror("[ERROR] - mmap() failed"); 49 | exit(1); 50 | } 51 | if (mem->align) { 52 | size_t error = (uint64_t) mem->buffer % mem->align; 53 | size_t left = error ? mem->align - error : 0; 54 | munmap(mem->buffer, left); 55 | mem->buffer += left; 56 | assert((uint64_t) mem->buffer % mem->align == 0); 57 | } 58 | 59 | if (mem->flags & F_VERBOSE) { 60 | fprintf(stderr, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 61 | fprintf(stderr, "[ MEM ] - Buffer: %p\n", mem->buffer); 62 | fprintf(stderr, "[ MEM ] - Size: %ld\n", alloc_size); 63 | fprintf(stderr, "[ MEM ] - Alignment: %ld\n", mem->align); 64 | fprintf(stderr, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 65 | } 66 | return 0; 67 | 68 | } 69 | 70 | int free_buffer(MemoryBuffer * mem) 71 | { 72 | free(mem->physmap); 73 | return munmap(mem->buffer, mem->size); 74 | } 75 | -------------------------------------------------------------------------------- /hammersuite/src/dram-address.c: -------------------------------------------------------------------------------- 1 | #include "dram-address.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "utils.h" 7 | 8 | #define DEBUG_REVERSE_FN 1 9 | 10 | extern DRAMLayout g_mem_layout; 11 | 12 | uint64_t get_dram_row(physaddr_t p_addr) 13 | { 14 | return (p_addr & g_mem_layout. 15 | row_mask) >> __builtin_ctzl(g_mem_layout.row_mask); 16 | } 17 | 18 | uint64_t get_dram_col(physaddr_t p_addr) 19 | { 20 | return (p_addr & g_mem_layout. 21 | col_mask) >> __builtin_ctzl(g_mem_layout.col_mask); 22 | } 23 | 24 | DRAMAddr phys_2_dram(physaddr_t p_addr) 25 | { 26 | 27 | DRAMAddr res = { 0, 0, 0 }; 28 | for (int i = 0; i < g_mem_layout.h_fns.len; i++) { 29 | res.bank |= 30 | (__builtin_parityl(p_addr & g_mem_layout.h_fns.lst[i]) << 31 | i); 32 | } 33 | 34 | res.row = get_dram_row(p_addr); 35 | res.col = get_dram_col(p_addr); 36 | 37 | return res; 38 | } 39 | 40 | physaddr_t dram_2_phys(DRAMAddr d_addr) 41 | { 42 | physaddr_t p_addr = 0; 43 | uint64_t col_val = 0; 44 | 45 | p_addr = (d_addr.row << __builtin_ctzl(g_mem_layout.row_mask)); // set row bits 46 | p_addr |= (d_addr.col << __builtin_ctzl(g_mem_layout.col_mask)); // set col bits 47 | 48 | for (int i = 0; i < g_mem_layout.h_fns.len; i++) { 49 | uint64_t masked_addr = p_addr & g_mem_layout.h_fns.lst[i]; 50 | // if the address already respects the h_fn then just move to the next func 51 | if (__builtin_parity(masked_addr) == ((d_addr.bank >> i) & 1L)) { 52 | continue; 53 | } 54 | // else flip a bit of the address so that the address respects the dram h_fn 55 | // that is get only bits not affecting the row. 56 | uint64_t h_lsb = __builtin_ctzl((g_mem_layout.h_fns.lst[i]) & 57 | ~(g_mem_layout.col_mask) & 58 | ~(g_mem_layout.row_mask)); 59 | p_addr ^= 1 << h_lsb; 60 | } 61 | 62 | #if DEBUG_REVERSE_FN 63 | int correct = 1; 64 | for (int i = 0; i < g_mem_layout.h_fns.len; i++) { 65 | 66 | if (__builtin_parity(p_addr & g_mem_layout.h_fns.lst[i]) != 67 | ((d_addr.bank >> i) & 1L)) { 68 | correct = 0; 69 | break; 70 | } 71 | } 72 | if (d_addr.row != ((p_addr & 73 | g_mem_layout.row_mask) >> 74 | __builtin_ctzl(g_mem_layout.row_mask))) 75 | correct = 0; 76 | if (!correct) 77 | fprintf(stderr, 78 | "[DEBUG] - Mapping function for 0x%lx not respected\n", 79 | p_addr); 80 | 81 | #endif 82 | 83 | return p_addr; 84 | } 85 | 86 | void set_global_dram_layout(DRAMLayout & mem_layout) 87 | { 88 | g_mem_layout = mem_layout; 89 | } 90 | 91 | DRAMLayout *get_dram_layout() 92 | { 93 | return &g_mem_layout; 94 | } 95 | 96 | bool d_addr_eq(DRAMAddr * d1, DRAMAddr * d2) 97 | { 98 | return (d1->bank == d2->bank) && (d1->row == d2->row) 99 | && (d1->col == d2->col); 100 | } 101 | 102 | bool d_addr_eq_row(DRAMAddr * d1, DRAMAddr * d2) 103 | { 104 | return (d1->bank == d2->bank) && (d1->row == d2->row); 105 | } 106 | 107 | uint64_t get_banks_cnt() 108 | { 109 | return 1 << g_mem_layout.h_fns.len; 110 | 111 | } 112 | 113 | char *dram_2_str(DRAMAddr * d_addr) 114 | { 115 | static char ret_str[1024]; 116 | sprintf(ret_str, "DRAM(bk: %ld (%s), row: %08ld, col: %08ld)", 117 | d_addr->bank, int_2_bin(d_addr->bank), d_addr->row, 118 | d_addr->col); 119 | return ret_str; 120 | } 121 | 122 | char *dramLayout_2_str(DRAMLayout * mem_layout) 123 | { 124 | static char ret_str[1024]; 125 | sprintf(ret_str, "{0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx} - 0x%lx\n", 126 | mem_layout->h_fns.lst[0], mem_layout->h_fns.lst[1], 127 | mem_layout->h_fns.lst[2], mem_layout->h_fns.lst[3], 128 | mem_layout->h_fns.lst[4], mem_layout->h_fns.lst[5], 129 | mem_layout->row_mask); 130 | return ret_str; 131 | } 132 | -------------------------------------------------------------------------------- /hammersuite/src/hammer-suite.c: -------------------------------------------------------------------------------- 1 | #include "include/hammer-suite.h" 2 | 3 | #include "include/memory.h" 4 | #include "include/utils.h" 5 | #include "include/allocator.h" 6 | #include "include/dram-address.h" 7 | #include "include/addr-mapper.h" 8 | #include "include/params.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define REFRESH_VAL "stdrefi" 25 | #define OUT_HEAD "f_og, f_new, vict_addr, aggr_addr\n" 26 | 27 | #define ROW_FIELD 1 28 | #define COL_FIELD 1<<1 29 | #define BK_FIELD 1<<2 30 | #define P_FIELD 1<<3 31 | #define ALL_FIELDS (ROW_FIELD | COL_FIELD | BK_FIELD) 32 | #define FLIPTABLE 33 | 34 | /* 35 | h_patt = hammer pattern (e.g., DOUBLE_SIDED) 36 | d_patt = data pattern (e.g., RANDOM) 37 | vict_addr = DRAMAddr for the bit flip in format bkXX.XrXXXX.cXXX 38 | f_og = byte original value 39 | f_new = byte after bit flip 40 | f_mask = bitmask of the bit flip 41 | base_row = initial row being hammered *in this round* 42 | row_cnt = number of rows being hammered *in this round* 43 | t_refi = t_refi 44 | h_rounds = number of hammering rounds 45 | aggr_addr = addresses of aggressor rows in format bkXX.rXXXX.cXX 46 | 47 | */ 48 | 49 | #define SHADOW_FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE) 50 | #define DEBUG 51 | 52 | #define NOP asm volatile ("NOP":::); 53 | #define NOP10 NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 54 | #define NOP100 NOP10 NOP10 NOP10 NOP10 NOP10 NOP10 NOP10 NOP10 NOP10 NOP10 55 | #define NOP1000 NOP100 NOP100 NOP100 NOP100 NOP100 NOP100 NOP100 NOP100 NOP100 NOP100 56 | 57 | extern ProfileParams *p; 58 | 59 | int g_bk; 60 | FILE *out_fd = NULL; 61 | static uint64_t CL_SEED = 0x7bc661612e71168c; 62 | 63 | static inline __attribute((always_inline)) 64 | char *cl_rand_gen(DRAMAddr * d_addr) 65 | { 66 | static uint64_t cl_buff[8]; 67 | for (int i = 0; i < 8; i++) { 68 | cl_buff[i] = 69 | __builtin_ia32_crc32di(CL_SEED, 70 | (d_addr->row + d_addr->bank + 71 | (d_addr->col + i*8))); 72 | } 73 | return (char *)cl_buff; 74 | } 75 | 76 | typedef struct { 77 | DRAMAddr *d_lst; 78 | size_t len; 79 | size_t rounds; 80 | } HammerPattern; 81 | 82 | typedef struct { 83 | DRAMAddr d_vict; 84 | uint8_t f_og; 85 | uint8_t f_new; 86 | HammerPattern *h_patt; 87 | } FlipVal; 88 | 89 | typedef struct { 90 | MemoryBuffer *mem; 91 | SessionConfig *cfg; 92 | DRAMAddr d_base; // base address for hammering 93 | ADDRMapper *mapper; // dram mapper 94 | 95 | int (*hammer_test) (void *self); 96 | } HammerSuite; 97 | 98 | char *dAddr_2_str(DRAMAddr d_addr, uint8_t fields) 99 | { 100 | static char ret_str[64]; 101 | char tmp_str[10]; 102 | bool first = true; 103 | memset(ret_str, 0x00, 64); 104 | if (fields & ROW_FIELD) { 105 | first = false; 106 | sprintf(tmp_str, "r%05ld", d_addr.row); 107 | strcat(ret_str, tmp_str); 108 | } 109 | if (fields & BK_FIELD) { 110 | if (!first) { 111 | strcat(ret_str, "."); 112 | } 113 | sprintf(tmp_str, "bk%02ld", d_addr.bank); 114 | strcat(ret_str, tmp_str); 115 | first = false; 116 | } 117 | if (fields & COL_FIELD) { 118 | if (!first) { 119 | strcat(ret_str, "."); 120 | } 121 | sprintf(tmp_str, "col%04ld", d_addr.col); 122 | strcat(ret_str, tmp_str); 123 | first = false; 124 | } 125 | return ret_str; 126 | } 127 | 128 | char *hPatt_2_str(HammerPattern * h_patt, int fields) 129 | { 130 | static char patt_str[256]; 131 | char *dAddr_str; 132 | 133 | memset(patt_str, 0x00, 256); 134 | 135 | for (int i = 0; i < h_patt->len; i++) { 136 | dAddr_str = dAddr_2_str(h_patt->d_lst[i], fields); 137 | strcat(patt_str, dAddr_str); 138 | if (i + 1 != h_patt->len) { 139 | strcat(patt_str, "/"); 140 | } 141 | 142 | } 143 | return patt_str; 144 | } 145 | 146 | void print_start_attack(HammerPattern *h_patt) 147 | { 148 | fprintf(out_fd, "%s : ", hPatt_2_str(h_patt, ROW_FIELD | BK_FIELD)); 149 | fflush(out_fd); 150 | } 151 | 152 | void print_end_attack() 153 | { 154 | fprintf(out_fd, "\n"); 155 | fflush(out_fd); 156 | } 157 | 158 | void export_flip(FlipVal * flip) 159 | { 160 | if (p->g_flags & F_VERBOSE) { 161 | fprintf(stdout, "[FLIP] - (%02x => %02x)\t vict: %s \taggr: %s \n", 162 | flip->f_og, flip->f_new, dAddr_2_str(flip->d_vict, ALL_FIELDS), 163 | hPatt_2_str(flip->h_patt, ROW_FIELD | BK_FIELD)); 164 | fflush(stdout); 165 | } 166 | 167 | #ifdef FLIPTABLE 168 | fprintf(out_fd, "%02x,%02x,%s ", flip->f_og, flip->f_new, 169 | dAddr_2_str(flip->d_vict, ALL_FIELDS)); 170 | #else 171 | fprintf(out_fd, "%02x,%02x,%s,%s\n", flip->f_og, flip->f_new, 172 | dAddr_2_str(flip->d_vict, ALL_FIELDS), hPatt_2_str(flip->h_patt, 173 | ROW_FIELD | BK_FIELD | P_FIELD)); 174 | #endif 175 | fflush(out_fd); 176 | } 177 | 178 | void export_cfg(HammerSuite * suite) 179 | { 180 | SessionConfig *cfg = suite->cfg; 181 | 182 | if (p->g_flags & F_VERBOSE) { 183 | fprintf(stdout, 184 | "Config: { h_cfg: %s, d_cfg: %s, h_rows: %ld, h_rounds: %ld, base: %s}\n", 185 | config_str[cfg->h_cfg], data_str[cfg->d_cfg], 186 | cfg->h_rows, cfg->h_rounds, dAddr_2_str(suite->d_base, 187 | ROW_FIELD | 188 | BK_FIELD)); 189 | } 190 | 191 | fprintf(out_fd, 192 | "# { h_cfg: %s, d_cfg: %s, h_rows: %ld, h_rounds: %ld, base: %s}\n", 193 | config_str[cfg->h_cfg], data_str[cfg->d_cfg], cfg->h_rows, 194 | cfg->h_rounds, dAddr_2_str(suite->d_base, 195 | ROW_FIELD | BK_FIELD)); 196 | fflush(out_fd); 197 | } 198 | 199 | void swap(char **lst, int i, int j) 200 | { 201 | char *tmp = lst[i]; 202 | lst[i] = lst[j]; 203 | lst[j] = tmp; 204 | } 205 | 206 | int random_int(int min, int max) 207 | { 208 | int number = min + rand() % (max - min); 209 | return number; 210 | } 211 | 212 | uint64_t hammer_it(HammerPattern* patt, MemoryBuffer* mem) { 213 | 214 | char** v_lst = (char**) malloc(sizeof(char*)*patt->len); 215 | for (size_t i = 0; i < patt->len; i++) { 216 | v_lst[i] = phys_2_virt(dram_2_phys(patt->d_lst[i]), mem); 217 | } 218 | 219 | sched_yield(); 220 | if (p->threshold > 0) { 221 | uint64_t t0 = 0, t1 = 0; 222 | // Threshold value depends on your system 223 | while (abs((int64_t) t1 - (int64_t) t0) < p->threshold) { 224 | t0 = rdtscp(); 225 | *(volatile char *)v_lst[0]; 226 | clflushopt(v_lst[0]); 227 | t1 = rdtscp(); 228 | } 229 | } 230 | 231 | 232 | uint64_t cl0, cl1; 233 | cl0 = realtime_now(); 234 | for ( int i = 0; i < patt->rounds; i++) { 235 | mfence(); 236 | for (size_t j = 0; j < patt->len; j++) { 237 | *(volatile char*) v_lst[j]; 238 | } 239 | for (size_t j = 0; j < patt->len; j++) { 240 | clflushopt(v_lst[j]); 241 | } 242 | } 243 | cl1 = realtime_now(); 244 | 245 | free(v_lst); 246 | return (cl1-cl0) / 1000000; 247 | 248 | } 249 | 250 | void __test_fill_random(char *addr, size_t size) 251 | { 252 | int fd; 253 | if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { 254 | perror("[ERROR] - Unable to open /dev/urandom"); 255 | exit(1); 256 | } 257 | if (read(fd, addr, size) == -1) { 258 | perror("[ERROR] - Unable to read /dev/urandom"); 259 | exit(1); 260 | } 261 | close(fd); 262 | 263 | } 264 | 265 | // DRAMAddr needs to be a copy in order to leave intact the original address 266 | void fill_stripe(DRAMAddr d_addr, uint8_t val, ADDRMapper * mapper) 267 | { 268 | for (size_t col = 0; col < ROW_SIZE; col += (1 << 6)) { 269 | d_addr.col = col; 270 | DRAM_pte d_pte = get_dram_pte(mapper, &d_addr); 271 | memset(d_pte.v_addr, val, CL_SIZE); 272 | } 273 | 274 | } 275 | 276 | void fill_row(HammerSuite *suite, DRAMAddr *d_addr, HammerData data_patt, int reverse) 277 | { 278 | if (p->vpat != (void *)NULL && p->tpat != (void *)NULL) { 279 | uint8_t pat = reverse ? *p->vpat : *p->tpat; 280 | fill_stripe(*d_addr, pat, suite->mapper); 281 | return; 282 | } 283 | 284 | if (reverse) { 285 | data_patt = (HammerData)((int)data_patt ^(int)REVERSE); 286 | } 287 | 288 | switch (data_patt) { 289 | case RANDOM: 290 | // rows are already filled for random data patt 291 | break; 292 | case ONE_TO_ZERO: 293 | fill_stripe(*d_addr, 0x00, suite->mapper); 294 | break; 295 | case ZERO_TO_ONE: 296 | fill_stripe(*d_addr, 0xff, suite->mapper); 297 | break; 298 | default: 299 | // fprintf(stderr, "[ERROR] - Wrong data pattern %d\n", data_patt); 300 | // exit(1); 301 | break; 302 | } 303 | 304 | } 305 | 306 | void cl_rand_fill(DRAM_pte * pte) 307 | { 308 | char *rand_data = cl_rand_gen(&pte->d_addr); 309 | memcpy(pte->v_addr, rand_data, CL_SIZE); 310 | } 311 | 312 | uint64_t cl_rand_comp(DRAM_pte * pte) 313 | { 314 | char *rand_data = cl_rand_gen(&pte->d_addr); 315 | uint64_t res = 0; 316 | for (int i = 0; i < CL_SIZE; i++) { 317 | if (*(pte->v_addr + i) != rand_data[i]) { 318 | res |= 1UL<mapper; 340 | DRAMAddr d_tmp; 341 | for (size_t bk = 0; bk < get_banks_cnt(); bk++) { 342 | d_tmp.bank = bk; 343 | for (size_t row = 0; row < suite->cfg->h_rows; row++) { 344 | d_tmp.row = suite->mapper->base_row + row; 345 | for (size_t col = 0; col < ROW_SIZE; col += (1 << 6)) { 346 | d_tmp.col = col; 347 | DRAM_pte d_pte = get_dram_pte(mapper, &d_tmp); 348 | cl_rand_fill(&d_pte); 349 | } 350 | } 351 | } 352 | } 353 | 354 | void init_stripe(HammerSuite * suite, uint8_t val) 355 | { 356 | ADDRMapper *mapper = suite->mapper; 357 | DRAMAddr d_tmp; 358 | for (size_t bk = 0; bk < get_banks_cnt(); bk++) { 359 | d_tmp.bank = bk; 360 | for (size_t row = 0; row < suite->cfg->h_rows; row++) { 361 | d_tmp.row = suite->mapper->base_row + row; 362 | for (size_t col = 0; col < ROW_SIZE; col += (1 << 6)) { 363 | d_tmp.col = col; 364 | DRAM_pte d_pte = get_dram_pte(mapper, &d_tmp); 365 | memset(d_pte.v_addr, val, CL_SIZE); 366 | } 367 | } 368 | } 369 | } 370 | 371 | void init_chunk(HammerSuite * suite) 372 | { 373 | 374 | if (p->vpat != (void *)NULL && p->tpat != (void *)NULL) { 375 | init_stripe(suite, (uint8_t) * p->vpat); 376 | return; 377 | } 378 | 379 | SessionConfig *cfg = suite->cfg; 380 | switch (cfg->d_cfg) { 381 | case RANDOM: 382 | init_random(suite); 383 | break; 384 | case ONE_TO_ZERO: 385 | init_stripe(suite, 0xff); 386 | break; 387 | case ZERO_TO_ONE: 388 | init_stripe(suite, 0x00); 389 | break; 390 | default: 391 | fprintf(stderr, "[ERROR] - Wrong data pattern %d\n", 392 | cfg->d_cfg); 393 | exit(1); 394 | break; 395 | } 396 | } 397 | 398 | void scan_random(HammerSuite * suite, HammerPattern * h_patt, size_t adj_rows) 399 | { 400 | ADDRMapper *mapper = suite->mapper; 401 | SessionConfig *cfg = suite->cfg; 402 | 403 | DRAMAddr d_tmp; 404 | FlipVal flip; 405 | 406 | d_tmp.bank = h_patt->d_lst[0].bank; 407 | 408 | for (size_t row = 0; row < cfg->h_rows; row++) { 409 | d_tmp.row = suite->mapper->base_row + row; 410 | for (size_t col = 0; col < ROW_SIZE; col += (1 << 6)) { 411 | d_tmp.col = col; 412 | DRAM_pte pte = get_dram_pte(mapper, &d_tmp); 413 | clflush(pte.v_addr); 414 | cpuid(); 415 | uint64_t res = cl_rand_comp(&pte); 416 | if (res) { 417 | char *rand_data = cl_rand_gen(&pte.d_addr); 418 | for (int off = 0; off < CL_SIZE; off++) { 419 | if (!((res >> off) & 1)) 420 | continue; 421 | d_tmp.col += off; 422 | 423 | flip.d_vict = d_tmp; 424 | flip.f_og = (uint8_t) rand_data[off]; 425 | flip.f_new = *(uint8_t *) (pte.v_addr + off); 426 | flip.h_patt = h_patt; 427 | assert(flip.f_og != flip.f_new); 428 | export_flip(&flip); 429 | 430 | } 431 | memcpy((char *)(pte.v_addr), rand_data, CL_SIZE); 432 | } 433 | } 434 | } 435 | } 436 | 437 | int find_flip(HammerSuite * suite, HammerPattern * h_patt, FlipVal *orig) 438 | { 439 | ADDRMapper *mapper = suite->mapper; 440 | SessionConfig *cfg = suite->cfg; 441 | 442 | DRAMAddr d_tmp; 443 | FlipVal flip;; 444 | 445 | d_tmp.bank = orig->d_vict.bank; 446 | d_tmp.row = orig->d_vict.row; 447 | d_tmp.col = orig->d_vict.col; 448 | 449 | DRAM_pte pte = get_dram_pte(mapper, &d_tmp); 450 | clflush(pte.v_addr); 451 | cpuid(); 452 | int off = cl_rand_comp(&pte); 453 | if (off != -1) { 454 | return 1; 455 | } 456 | 457 | return 0; 458 | } 459 | 460 | bool in_hPatt(DRAMAddr * d_addr, HammerPattern * h_patt) 461 | { 462 | for (int i = 0; i < h_patt->len; i++) { 463 | if (d_addr_eq_row(&h_patt->d_lst[i], d_addr)) 464 | return true; 465 | } 466 | return false; 467 | } 468 | 469 | uint64_t cl_stripe_cmp(DRAM_pte * pte, uint8_t val) 470 | { 471 | uint64_t res = 0; 472 | #ifdef POINTER_CHAISING 473 | for (int_t i = 8; i < CL_SIZE; i++) { 474 | #else 475 | for (int i = 0; i < CL_SIZE; i++) { 476 | #endif 477 | if (*(uint8_t*) (pte->v_addr + i) != val) { 478 | res |= 1UL<mapper; 488 | SessionConfig *cfg = suite->cfg; 489 | 490 | DRAMAddr d_tmp; 491 | FlipVal flip; 492 | 493 | d_tmp.bank = h_patt->d_lst[0].bank; 494 | uint8_t t_val = val; 495 | 496 | for (size_t row = 0; row < cfg->h_rows; row++) { 497 | d_tmp.row = suite->mapper->base_row + row; 498 | t_val = val; 499 | if (in_hPatt(&d_tmp, h_patt)) 500 | if (p->tpat != (void *)NULL && p->vpat != (void *)NULL) 501 | t_val = (uint8_t) * p->tpat; 502 | else 503 | t_val ^= 0xff; 504 | 505 | for (size_t col = 0; col < ROW_SIZE; col += (1 << 6)) { 506 | d_tmp.col = col; 507 | DRAM_pte pte = get_dram_pte(mapper, &d_tmp); 508 | clflush(pte.v_addr); 509 | cpuid(); 510 | 511 | uint64_t res = cl_stripe_cmp(&pte, t_val); 512 | if (res) { 513 | for (int off = 0; off < CL_SIZE; off++) { 514 | if (!((res >> off) & 1)) 515 | continue; 516 | d_tmp.col += off; 517 | 518 | flip.d_vict = d_tmp; 519 | flip.f_og = (uint8_t) t_val; 520 | flip.f_new = *(uint8_t *) (pte.v_addr + off); 521 | flip.h_patt = h_patt; 522 | export_flip(&flip); 523 | memset(pte.v_addr + off, t_val, 1); 524 | } 525 | memset((char *)(pte.v_addr), t_val, CL_SIZE); 526 | } 527 | } 528 | } 529 | } 530 | 531 | // TODO adj_rows should tell how many rows to scan out of the bank. Not currently used 532 | void scan_rows(HammerSuite * suite, HammerPattern * h_patt, size_t adj_rows) 533 | { 534 | if (p->vpat != (void *)NULL && p->tpat != (void *)NULL) { 535 | scan_stripe(suite, h_patt, adj_rows, (uint8_t) * p->vpat); 536 | return; 537 | } 538 | 539 | SessionConfig *cfg = suite->cfg; 540 | switch (cfg->d_cfg) { 541 | case RANDOM: 542 | // rows are already filled for random data patt 543 | scan_random(suite, h_patt, adj_rows); 544 | break; 545 | case ONE_TO_ZERO: 546 | scan_stripe(suite, h_patt, adj_rows, 0xff); 547 | break; 548 | case ZERO_TO_ONE: 549 | scan_stripe(suite, h_patt, adj_rows, 0x00); 550 | break; 551 | default: 552 | fprintf(stderr, "[ERROR] - Wrong data pattern %d\n", 553 | cfg->d_cfg); 554 | exit(1); 555 | break; 556 | } 557 | } 558 | 559 | int free_triple_sided_test(HammerSuite * suite) 560 | { 561 | MemoryBuffer *mem = suite->mem; 562 | SessionConfig *cfg = suite->cfg; 563 | 564 | DRAMAddr d_base = suite->d_base; 565 | d_base.col = 0; 566 | HammerPattern h_patt; 567 | 568 | h_patt.len = 3; 569 | h_patt.rounds = cfg->h_rounds; 570 | 571 | h_patt.d_lst = (DRAMAddr *) malloc(sizeof(DRAMAddr) * h_patt.len); 572 | memset(h_patt.d_lst, 0x00, sizeof(DRAMAddr) * h_patt.len); 573 | 574 | init_chunk(suite); 575 | fprintf(stderr, "CL_SEED: %lx\n", CL_SEED); 576 | 577 | h_patt.d_lst[0] = d_base; 578 | for (int r0 = 1; r0 < cfg->h_rows; r0++) { 579 | for (int r1 = r0; r1 < cfg->h_rows; r1++) { 580 | if (r0 == r1) 581 | continue; 582 | 583 | h_patt.d_lst[1].row = h_patt.d_lst[0].row + r0; 584 | h_patt.d_lst[2].row = h_patt.d_lst[0].row + r1; 585 | h_patt.d_lst[0].bank = 0; 586 | h_patt.d_lst[1].bank = 0; 587 | h_patt.d_lst[2].bank = 0; 588 | fprintf(stderr, "[HAMMER] - %s: ", hPatt_2_str(&h_patt, ROW_FIELD)); 589 | for (size_t bk = 0; bk < get_banks_cnt(); bk++) { 590 | h_patt.d_lst[0].bank = bk; 591 | h_patt.d_lst[1].bank = bk; 592 | h_patt.d_lst[2].bank = bk; 593 | // fill all the aggressor rows 594 | for (int idx = 0; idx < 3; idx++) { 595 | fill_row(suite, &h_patt.d_lst[idx], cfg->d_cfg, 0); 596 | } 597 | uint64_t time = hammer_it(&h_patt, mem); 598 | fprintf(stderr, "%ld ", time); 599 | 600 | scan_rows(suite, &h_patt, 0); 601 | for (int idx = 0; idx < 3; idx++) { 602 | fill_row(suite, &h_patt.d_lst[idx], cfg->d_cfg, 1); 603 | } 604 | } 605 | fprintf(stderr, "\n"); 606 | } 607 | } 608 | free(h_patt.d_lst); 609 | } 610 | 611 | int assisted_double_sided_test(HammerSuite * suite) 612 | { 613 | MemoryBuffer *mem = suite->mem; 614 | SessionConfig *cfg = suite->cfg; 615 | DRAMAddr d_base = suite->d_base; 616 | d_base.col = 0; 617 | 618 | HammerPattern h_patt; 619 | 620 | h_patt.len = 3; 621 | h_patt.rounds = cfg->h_rounds; 622 | 623 | h_patt.d_lst = (DRAMAddr *) malloc(sizeof(DRAMAddr) * h_patt.len); 624 | memset(h_patt.d_lst, 0x00, sizeof(DRAMAddr) * h_patt.len); 625 | 626 | init_chunk(suite); 627 | fprintf(stderr, "CL_SEED: %lx\n", CL_SEED); 628 | h_patt.d_lst[0] = d_base; 629 | 630 | for (int r0 = 1; r0 < cfg->h_rows; r0++) { 631 | h_patt.d_lst[1].row = d_base.row + r0; 632 | h_patt.d_lst[2].row = h_patt.d_lst[1].row + 2; 633 | h_patt.d_lst[0].row = 634 | d_base.row + get_rnd_int(0, cfg->h_rows - 1); 635 | while (h_patt.d_lst[0].row == h_patt.d_lst[1].row 636 | || h_patt.d_lst[0].row == h_patt.d_lst[2].row) 637 | h_patt.d_lst[0].row = 638 | d_base.row + get_rnd_int(0, cfg->h_rows - 1); 639 | 640 | if (h_patt.d_lst[2].row >= d_base.row + cfg->h_rows) 641 | break; 642 | 643 | h_patt.d_lst[0].bank = 0; 644 | h_patt.d_lst[1].bank = 0; 645 | h_patt.d_lst[2].bank = 0; 646 | fprintf(stderr, "[HAMMER] - %s: ", hPatt_2_str(&h_patt, ROW_FIELD)); 647 | for (size_t bk = 0; bk < get_banks_cnt(); bk++) { 648 | h_patt.d_lst[0].bank = bk; 649 | h_patt.d_lst[1].bank = bk; 650 | h_patt.d_lst[2].bank = bk; 651 | // fill all the aggressor rows 652 | for (int idx = 0; idx < 3; idx++) { 653 | fill_row(suite, &h_patt.d_lst[idx], cfg->d_cfg, 0); 654 | // fprintf(stderr, "d_addr: %s\n", dram_2_str(&h_patt.d_lst[idx])); 655 | } 656 | // fprintf(stderr, "d_addr: %s\n", dram_2_str(&h_patt.d_lst[idx])); 657 | uint64_t time = hammer_it(&h_patt, mem); 658 | fprintf(stderr, "%ld ", time); 659 | 660 | scan_rows(suite, &h_patt, 0); 661 | for (int idx = 0; idx<3; idx++) { 662 | fill_row(suite, &h_patt.d_lst[idx], cfg->d_cfg, 1); 663 | } 664 | } 665 | fprintf(stderr, "\n"); 666 | } 667 | free(h_patt.d_lst); 668 | } 669 | 670 | int n_sided_test(HammerSuite * suite) 671 | { 672 | MemoryBuffer *mem = suite->mem; 673 | SessionConfig *cfg = suite->cfg; 674 | DRAMAddr d_base = suite->d_base; 675 | d_base.col = 0; 676 | /* d_base.row = 20480; */ 677 | /* d_base.row = 16400; */ 678 | HammerPattern h_patt; 679 | 680 | h_patt.len = cfg->aggr_n; 681 | h_patt.rounds = cfg->h_rounds; 682 | 683 | h_patt.d_lst = (DRAMAddr *) malloc(sizeof(DRAMAddr) * h_patt.len); 684 | memset(h_patt.d_lst, 0x00, sizeof(DRAMAddr) * h_patt.len); 685 | 686 | init_chunk(suite); 687 | fprintf(stderr, "CL_SEED: %lx\n", CL_SEED); 688 | h_patt.d_lst[0] = d_base; 689 | 690 | const int mem_to_hammer = 256 << 20; 691 | const int n_rows = mem_to_hammer / ((8<<10) * get_banks_cnt()); 692 | fprintf(stderr, "Hammering %d rows per bank\n", n_rows); 693 | for (int r0 = 1; r0 < n_rows; r0++) { 694 | h_patt.d_lst[0].row = d_base.row + r0; 695 | int k = 1; 696 | for (; k < cfg->aggr_n; k++) { 697 | h_patt.d_lst[k].row = h_patt.d_lst[k - 1].row + 2; 698 | h_patt.d_lst[k].bank = 0; 699 | } 700 | if (h_patt.d_lst[k - 1].row >= d_base.row + cfg->h_rows) 701 | break; 702 | 703 | fprintf(stderr, "[HAMMER] - %s: ", hPatt_2_str(&h_patt, ROW_FIELD)); 704 | for (size_t bk = 0; bk < get_banks_cnt(); bk++) { 705 | 706 | for (int s = 0; s < cfg->aggr_n; s++) { 707 | h_patt.d_lst[s].bank = bk; 708 | } 709 | #ifdef FLIPTABLE 710 | print_start_attack(&h_patt); 711 | #endif 712 | // fill all the aggressor rows 713 | for (int idx = 0; idx < cfg->aggr_n; idx++) { 714 | fill_row(suite, &h_patt.d_lst[idx], cfg->d_cfg, 0); 715 | } 716 | 717 | uint64_t time = hammer_it(&h_patt, mem); 718 | fprintf(stderr, "%ld ", time); 719 | 720 | scan_rows(suite, &h_patt, 0); 721 | for (int idx = 0; idxd_cfg, 1); 723 | } 724 | #ifdef FLIPTABLE 725 | print_end_attack(); 726 | #endif 727 | } 728 | fprintf(stderr, "\n"); 729 | } 730 | free(h_patt.d_lst); 731 | } 732 | 733 | void fuzz(HammerSuite *suite, int d, int v) 734 | { 735 | int i; 736 | HammerPattern h_patt; 737 | SessionConfig *cfg = suite->cfg; 738 | h_patt.rounds = cfg->h_rounds; 739 | h_patt.len = cfg->aggr_n; 740 | 741 | h_patt.d_lst = (DRAMAddr *) malloc(sizeof(DRAMAddr) * h_patt.len); 742 | memset(h_patt.d_lst, 0x00, sizeof(DRAMAddr) * h_patt.len); 743 | 744 | init_chunk(suite); 745 | int offset = random_int(1, 32); 746 | 747 | h_patt.d_lst[0] = suite->d_base; 748 | h_patt.d_lst[0].row = suite->d_base.row + offset; 749 | 750 | h_patt.d_lst[1] = suite->d_base; 751 | h_patt.d_lst[1].row = h_patt.d_lst[0].row + v + 1; 752 | for (i = 2; i < h_patt.len-1; i+=2) { 753 | h_patt.d_lst[i] = suite->d_base; 754 | h_patt.d_lst[i].row = h_patt.d_lst[i-1].row + d + 1; 755 | h_patt.d_lst[i+1] = suite->d_base; 756 | h_patt.d_lst[i+1].row = h_patt.d_lst[i].row + v + 1; 757 | } 758 | if (h_patt.len % 2) { 759 | h_patt.d_lst[h_patt.len-1] = suite->d_base; 760 | h_patt.d_lst[h_patt.len-1].row = h_patt.d_lst[h_patt.len-2].row + d + 1; 761 | } 762 | 763 | fprintf(stderr, "[HAMMER] - %s: ", hPatt_2_str(&h_patt, ROW_FIELD)); 764 | for (int bk = 0; bk < get_banks_cnt(); bk++) 765 | { 766 | for (int idx = 0; idx < h_patt.len; idx++) { 767 | h_patt.d_lst[idx].bank = bk; 768 | } 769 | #ifdef FLIPTABLE 770 | print_start_attack(&h_patt); 771 | #endif 772 | for (int idx = 0; idx < h_patt.len; idx++) 773 | fill_row(suite, &h_patt.d_lst[idx], suite->cfg->d_cfg, 0); 774 | 775 | uint64_t time = hammer_it(&h_patt, suite->mem); 776 | fprintf(stderr, "%lu ",time); 777 | 778 | scan_rows(suite, &h_patt, 0); 779 | for (int idx = 0; idxcfg->d_cfg, 1); 781 | } 782 | 783 | #ifdef FLIPTABLE 784 | print_end_attack(); 785 | #endif 786 | } 787 | fprintf(stdout, "\n"); 788 | free(h_patt.d_lst); 789 | } 790 | 791 | void create_dir(const char* dir_name) 792 | { 793 | struct stat st = {0}; 794 | if (stat(dir_name, &st) == -1) { 795 | mkdir(dir_name, 0777); 796 | } 797 | } 798 | 799 | void fuzzing_session(SessionConfig * cfg, MemoryBuffer * mem) 800 | { 801 | int d, v, aggrs; 802 | 803 | srand(CL_SEED); 804 | DRAMAddr d_base = phys_2_dram(virt_2_phys(mem->buffer, mem)); 805 | fprintf(stdout, "[INFO] d_base.row:%lu\n", d_base.row); 806 | 807 | /* Init FILES */ 808 | create_dir(DATA_DIR); 809 | char *out_name = (char *)malloc(500); 810 | char rows_str[10]; 811 | strcpy(out_name, DATA_DIR); 812 | strcat(out_name, p->g_out_prefix); 813 | strcat(out_name, "."); 814 | strcat(out_name, "fuzzing"); 815 | strcat(out_name, "."); 816 | sprintf(rows_str, "%08ld", d_base.row); 817 | strcat(out_name, rows_str); 818 | strcat(out_name, "."); 819 | sprintf(rows_str, "%ld", cfg->h_rounds); 820 | strcat(out_name, rows_str); 821 | strcat(out_name, "."); 822 | strcat(out_name, REFRESH_VAL); 823 | strcat(out_name, ".csv"); 824 | if (p->g_flags & F_NO_OVERWRITE) { 825 | int cnt = 0; 826 | char *tmp_name = (char *)malloc(500); 827 | strncpy(tmp_name, out_name, strlen(out_name)); 828 | while (access(tmp_name, F_OK) != -1) { 829 | cnt++; 830 | sprintf(tmp_name, "%s.%02d", out_name, cnt); 831 | } 832 | strncpy(out_name, tmp_name, strlen(tmp_name)); 833 | free(tmp_name); 834 | } 835 | out_fd = fopen(out_name, "w+"); 836 | assert(out_fd != NULL); 837 | 838 | HammerSuite *suite = (HammerSuite *) malloc(sizeof(HammerSuite)); 839 | suite->mem = mem; 840 | suite->cfg = cfg; 841 | suite->d_base = d_base; 842 | suite->mapper = (ADDRMapper *) malloc(sizeof(ADDRMapper)); 843 | init_addr_mapper(suite->mapper, mem, &suite->d_base, cfg->h_rows); 844 | 845 | while(1) { 846 | cfg->aggr_n = random_int(2, 32); 847 | d = random_int(0, 16); 848 | v = random_int(1, 4); 849 | fuzz(suite, d, v); 850 | } 851 | } 852 | 853 | void hammer_session(SessionConfig * cfg, MemoryBuffer * memory) 854 | { 855 | MemoryBuffer mem = *memory; 856 | 857 | DRAMAddr d_base = phys_2_dram(virt_2_phys(mem.buffer, &mem)); 858 | d_base.row += cfg->base_off; 859 | 860 | create_dir(DATA_DIR); 861 | char *out_name = (char *)malloc(500); 862 | char rows_str[10]; 863 | strcpy(out_name, DATA_DIR); 864 | strcat(out_name, p->g_out_prefix); 865 | strcat(out_name, "."); 866 | 867 | if (cfg->h_cfg) { 868 | char config[15]; 869 | sprintf(config, config_str[cfg->h_cfg], cfg->aggr_n); 870 | strcat(out_name, config); 871 | } else { 872 | strcat(out_name, config_str[cfg->h_cfg]); 873 | } 874 | strcat(out_name, "."); 875 | sprintf(rows_str, "%08ld", d_base.row); 876 | strcat(out_name, rows_str); 877 | strcat(out_name, "."); 878 | sprintf(rows_str, "%03ld", cfg->h_rows); 879 | strcat(out_name, rows_str); 880 | strcat(out_name, "."); 881 | sprintf(rows_str, "%ld", cfg->h_rounds); 882 | strcat(out_name, rows_str); 883 | strcat(out_name, "."); 884 | strcat(out_name, REFRESH_VAL); 885 | strcat(out_name, ".csv"); 886 | if (p->g_flags & F_NO_OVERWRITE) { 887 | int cnt = 0; 888 | char *tmp_name = (char *)malloc(500); 889 | strncpy(tmp_name, out_name, strlen(out_name)); 890 | while (access(tmp_name, F_OK) != -1) { 891 | cnt++; 892 | sprintf(tmp_name, "%s.%02d", out_name, cnt); 893 | } 894 | strncpy(out_name, tmp_name, strlen(tmp_name)); 895 | free(tmp_name); 896 | } 897 | out_fd = fopen(out_name, "w+"); 898 | 899 | fprintf(stderr, 900 | "[LOG] - Hammer session! access pattern: %s\t data pattern: %s\n", 901 | config_str[cfg->h_cfg], data_str[cfg->d_cfg]); 902 | fprintf(stderr, "[LOG] - File: %s\n", out_name); 903 | 904 | HammerSuite *suite = (HammerSuite *) malloc(sizeof(HammerSuite)); 905 | suite->cfg = cfg; 906 | suite->mem = &mem; 907 | suite->d_base = d_base; 908 | suite->mapper = (ADDRMapper *) malloc(sizeof(ADDRMapper)); 909 | init_addr_mapper(suite->mapper, &mem, &suite->d_base, cfg->h_rows); 910 | 911 | #ifndef FLIPTABLE 912 | export_cfg(suite); // export the configuration of the experiment to file. 913 | fprintf(out_fd, OUT_HEAD); 914 | #endif 915 | 916 | switch (cfg->h_cfg) { 917 | case ASSISTED_DOUBLE_SIDED: 918 | { 919 | suite->hammer_test = 920 | (int (*)(void *))assisted_double_sided_test; 921 | break; 922 | } 923 | case FREE_TRIPLE_SIDED: 924 | { 925 | suite->hammer_test = 926 | (int (*)(void *))free_triple_sided_test; 927 | break; 928 | } 929 | case N_SIDED: 930 | { 931 | assert(cfg->aggr_n > 1); 932 | suite->hammer_test = (int (*)(void *))n_sided_test; 933 | break; 934 | } 935 | default: 936 | { 937 | suite->hammer_test = (int (*)(void *))n_sided_test; 938 | } 939 | } 940 | 941 | suite->hammer_test(suite); 942 | fclose(out_fd); 943 | tear_down_addr_mapper(suite->mapper); 944 | free(suite); 945 | } 946 | -------------------------------------------------------------------------------- /hammersuite/src/include/addr-mapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "memory.h" 4 | #include "types.h" 5 | #include "dram-address.h" 6 | 7 | typedef struct { 8 | DRAMAddr d_addr; 9 | char *v_addr; 10 | } DRAM_pte; 11 | 12 | typedef struct { 13 | DRAM_pte *lst; 14 | size_t len; 15 | } RowMap; 16 | 17 | typedef struct { 18 | size_t base_row; // used as an offset 19 | RowMap *row_maps; 20 | } ADDRMapper; 21 | 22 | void init_addr_mapper(ADDRMapper * mapper, MemoryBuffer * mem, 23 | DRAMAddr * d_base, size_t h_rows); 24 | RowMap get_row_map(ADDRMapper * mapper, DRAMAddr * d_addr); 25 | DRAM_pte get_dram_pte(ADDRMapper * mapper, DRAMAddr * d_addr); 26 | void tear_down_addr_mapper(ADDRMapper * mapper); 27 | -------------------------------------------------------------------------------- /hammersuite/src/include/allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | int alloc_buffer(MemoryBuffer * mem); 6 | int free_buffer(MemoryBuffer * mem); 7 | -------------------------------------------------------------------------------- /hammersuite/src/include/dram-address.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | #define HASH_FN_CNT 6 6 | 7 | typedef struct { 8 | uint64_t lst[HASH_FN_CNT]; 9 | uint64_t len; 10 | } AddrFns; 11 | 12 | typedef struct { 13 | AddrFns h_fns; 14 | uint64_t row_mask; 15 | uint64_t col_mask; 16 | } DRAMLayout; 17 | 18 | typedef struct { 19 | /* bank is a simplified addressing of 20 | where all this will eventually map to a specific bank */ 21 | uint64_t bank; 22 | uint64_t row; 23 | uint64_t col; 24 | } DRAMAddr; 25 | 26 | physaddr_t dram_2_phys(DRAMAddr d_addr); 27 | DRAMAddr phys_2_dram(physaddr_t p_addr); 28 | char *dram_2_str(DRAMAddr * d_addr); 29 | char *dramLayout_2_str(DRAMLayout * mem_layout); 30 | DRAMLayout *get_dram_layout(); 31 | uint64_t get_banks_cnt(); 32 | bool d_addr_eq(DRAMAddr * d1, DRAMAddr * d2); 33 | bool d_addr_eq_row(DRAMAddr * d1, DRAMAddr * d2); 34 | -------------------------------------------------------------------------------- /hammersuite/src/include/hammer-suite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "types.h" 6 | 7 | void hammer_session(SessionConfig * cfg, MemoryBuffer * memory); 8 | void fuzzing_session(SessionConfig * cfg, MemoryBuffer * memory); 9 | -------------------------------------------------------------------------------- /hammersuite/src/include/memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | #include 5 | 6 | void set_physmap(MemoryBuffer * mem); 7 | physaddr_t virt_2_phys(char *v_addr, MemoryBuffer * mem); 8 | char *phys_2_virt(physaddr_t p_addr, MemoryBuffer * mem); 9 | -------------------------------------------------------------------------------- /hammersuite/src/include/params.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Vrije Universiteit Amsterdam 3 | * 4 | * This program is licensed under the GPL2+. 5 | */ 6 | 7 | #ifndef PARAMS_H 8 | #define PARAMS_H 1 9 | 10 | #include 11 | #include 12 | 13 | #define ROUNDS_std 1000000 14 | #define HUGETLB_std "/mnt/huge/buff" 15 | #define CONFIG_NAME_std "tmp/s_cfg.bin" 16 | #define O_FILE_std "DIMM00" 17 | #define ALLOC_SIZE 1<<30 18 | #define ALIGN_std 2<<20 19 | #define PATT_LEN 1024 20 | #define AGGR_std 2 21 | #define HUGE_YES 22 | 23 | typedef struct ProfileParams { 24 | uint64_t g_flags = 0; 25 | char *g_out_prefix; 26 | char *tpat = (char *)NULL; 27 | char *vpat = (char *)NULL; 28 | int threshold = 0; 29 | int fuzzing = 0; // start fuzzing!! 30 | size_t m_size = ALLOC_SIZE; 31 | size_t m_align = ALIGN_std; 32 | size_t rounds = ROUNDS_std; 33 | size_t base_off = 0; 34 | char *huge_file = (char *)HUGETLB_std; 35 | int huge_fd; 36 | char *conf_file = (char *)CONFIG_NAME_std; 37 | int aggr = AGGR_std; 38 | } ProfileParams; 39 | 40 | int process_argv(int argc, char *argv[], ProfileParams *params); 41 | 42 | #endif /* params.h */ 43 | -------------------------------------------------------------------------------- /hammersuite/src/include/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define STRIPE_SHIFT 0 // not needed anymore 8 | #define O2Z (0b01 << STRIPE_SHIFT) // ONE_TO_ZERO 9 | #define Z2O (0b10 << STRIPE_SHIFT) // ZERO_TO_ONE 10 | #define REVERSE_VAL (O2Z ^ Z2O) // if you xor REVERSE with one of the stripe val it will give you the opposite 11 | 12 | static const char *config_str[] = 13 | { "assisted-dbl", "free-triple", "%i_sided"}; 14 | static const char *data_str[] = { "random", "i2o", "o2i" }; 15 | 16 | typedef enum { 17 | ASSISTED_DOUBLE_SIDED, 18 | FREE_TRIPLE_SIDED, 19 | N_SIDED, 20 | } HammerConfig; 21 | 22 | typedef enum { 23 | RANDOM, 24 | ONE_TO_ZERO = O2Z, 25 | ZERO_TO_ONE = Z2O, 26 | REVERSE = REVERSE_VAL 27 | } HammerData; 28 | 29 | typedef uint64_t physaddr_t; 30 | 31 | /* not necessarily page-aligned addresses. 32 | used only to keep track of virt<->phys mapping. */ 33 | typedef struct { 34 | char *v_addr; 35 | physaddr_t p_addr; 36 | } pte_t; 37 | 38 | typedef struct { 39 | HammerConfig h_cfg; 40 | HammerData d_cfg; 41 | size_t h_rows; 42 | size_t h_rounds; 43 | size_t base_off; // offset from the beginning of the contig chunk 44 | int aggr_n; 45 | } SessionConfig; 46 | 47 | typedef struct { 48 | char *buffer; // base addr 49 | pte_t *physmap; // list of virt<->phys mapping for every page 50 | int fd; // fd in the case of mmap hugetlbfs 51 | uint64_t size; // in bytes 52 | uint64_t align; 53 | uint64_t flags; // from params 54 | } MemoryBuffer; 55 | -------------------------------------------------------------------------------- /hammersuite/src/include/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define BIT_SET(x) (1ULL<<(x)) 8 | #define BIT_VAL(b,val) (((val) >> (b)) & 1) 9 | #define KB(x) ((x)<<10ULL) 10 | #define MB(x) ((x)<<20ULL) 11 | #define GB(x) ((x)<<30ULL) 12 | #define CL_SHIFT 6 13 | #define CL_SIZE 64 14 | #define PAGE_SIZE 4096 15 | #define ROW_SIZE (8<<10) 16 | 17 | #define ALIGN_TO(X, Y) ((X) & (~((1LL<<(Y))-1LL))) // Mask out the lower Y bits 18 | #define LS_BITMASK(X) ((1LL<<(X))-1LL) // Mask only the lower X bits 19 | 20 | // Flags 21 | #define F_CLEAR 0L 22 | #define F_VERBOSE BIT_SET(0) 23 | #define F_EXPORT BIT_SET(1) 24 | #define F_CONFIG BIT_SET(2) 25 | #define F_NO_OVERWRITE BIT_SET(3) 26 | #define MEM_SHIFT (30L) 27 | #define MEM_MASK 0b11111ULL << MEM_SHIFT 28 | #define F_ALLOC_HUGE BIT_SET(MEM_SHIFT) 29 | #define F_ALLOC_HUGE_1G F_ALLOC_HUGE | BIT_SET(MEM_SHIFT+1) 30 | #define F_ALLOC_HUGE_2M F_ALLOC_HUGE | BIT_SET(MEM_SHIFT+2) 31 | #define F_POPULATE BIT_SET(MEM_SHIFT+3) 32 | 33 | #define NOT_FOUND ((void*) -1) 34 | #define NOT_OPENED -1 35 | 36 | #define TIMESPEC_NSEC(ts) ((ts)->tv_sec * 1e9 + (ts)->tv_nsec) 37 | 38 | //---------------------------------------------------------- 39 | // Static functions 40 | 41 | static inline __attribute__ ((always_inline)) 42 | void clflush(volatile void *p) 43 | { 44 | asm volatile ("clflush (%0)\n"::"r" (p):"memory"); 45 | } 46 | 47 | static inline __attribute__ ((always_inline)) 48 | void clflushopt(volatile void *p) 49 | { 50 | #ifdef DDR3 51 | asm volatile ("clflush (%0)\n"::"r" (p):"memory"); 52 | #else 53 | asm volatile ("clflushopt (%0)\n"::"r" (p):"memory"); 54 | # 55 | #endif 56 | } 57 | 58 | static inline __attribute__ ((always_inline)) 59 | void cpuid() 60 | { 61 | asm volatile ("cpuid":::"rax", "rbx", "rcx", "rdx"); 62 | } 63 | 64 | static inline __attribute__ ((always_inline)) 65 | void mfence() 66 | { 67 | asm volatile ("mfence":::"memory"); 68 | } 69 | 70 | static inline __attribute__ ((always_inline)) 71 | void sfence() 72 | { 73 | asm volatile ("sfence":::"memory"); 74 | } 75 | 76 | static inline __attribute__ ((always_inline)) 77 | void lfence() 78 | { 79 | asm volatile ("lfence":::"memory"); 80 | } 81 | 82 | static inline __attribute__ ((always_inline)) 83 | uint64_t rdtscp(void) 84 | { 85 | uint64_t lo, hi; 86 | asm volatile ("rdtscp\n":"=a" (lo), "=d"(hi) 87 | ::"%rcx"); 88 | return (hi << 32) | lo; 89 | } 90 | 91 | static inline __attribute__ ((always_inline)) 92 | uint64_t rdtsc(void) 93 | { 94 | uint64_t lo, hi; 95 | asm volatile ("rdtsc\n":"=a" (lo), "=d"(hi) 96 | ::"%rcx"); 97 | return (hi << 32) | lo; 98 | } 99 | 100 | static inline __attribute__ ((always_inline)) 101 | uint64_t realtime_now() 102 | { 103 | struct timespec now_ts; 104 | clock_gettime(CLOCK_MONOTONIC, &now_ts); 105 | return TIMESPEC_NSEC(&now_ts); 106 | } 107 | 108 | // void set_physmap(mem_buff_t* mem); 109 | 110 | // pte_t get_pte(char* v_addr, mem_buff_t* mem); 111 | 112 | // addr_tuple reverse_addr_tuple(uint64_t p_addr, mem_buff_t* mem); 113 | 114 | //---------------------------------------------------------- 115 | // Helpers 116 | int gt(const void *a, const void *b); 117 | 118 | double mean(uint64_t * vals, size_t size); 119 | 120 | uint64_t median(uint64_t * vals, size_t size); 121 | 122 | char *bit_string(uint64_t val); 123 | 124 | char *int_2_bin(uint64_t val); 125 | 126 | char *get_rnd_addr(char *base, size_t m_size, size_t align); 127 | 128 | int get_rnd_int(int min, int max); 129 | -------------------------------------------------------------------------------- /hammersuite/src/main.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | // #include /* for rdtsc, rdtscp, clflush */ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "include/utils.h" 19 | #include "include/types.h" 20 | #include "include/allocator.h" 21 | #include "include/memory.h" 22 | #include "include/dram-address.h" 23 | #include "include/hammer-suite.h" 24 | #include "include/params.h" 25 | 26 | ProfileParams *p; 27 | 28 | // DRAMLayout g_mem_layout = {{{0x4080,0x88000,0x110000,0x220000,0x440000,0x4b300}, 6}, 0xffff80000, ((1<<13)-1)}; 29 | // DRAMLayout g_mem_layout = { {{0x2040, 0x44000, 0x88000, 0x110000, 0x220000}, 5}, 0xffffc0000, ((1 << 13) - 1) }; 30 | // DRAMLayout g_mem_layout = {{{0x2040,0x24000,0x48000,0x90000},4}, 0xffffe0000, ((1<<13)-1)}; 31 | DRAMLayout g_mem_layout = {{{0x4080,0x48000,0x90000,0x120000,0x1b300}, 5}, 0xffffc0000, ROW_SIZE-1}; 32 | 33 | void read_config(SessionConfig * cfg, char *f_name) 34 | { 35 | FILE *fp = fopen(f_name, "rb"); 36 | int p_size; 37 | size_t res; 38 | assert(fp != NULL); 39 | res = fread(cfg, sizeof(SessionConfig), 1, fp); 40 | assert(res == 1); 41 | fclose(fp); 42 | return; 43 | } 44 | 45 | void gmem_dump() 46 | { 47 | FILE *fp = fopen("g_mem_dump.bin", "wb+"); 48 | fwrite(&g_mem_layout, sizeof(DRAMLayout), 1, fp); 49 | fclose(fp); 50 | 51 | #ifdef DEBUG 52 | DRAMLayout tmp; 53 | fp = fopen("g_mem_dump.bin", "rb"); 54 | fread(&tmp, sizeof(DRAMLayout), 1, fp); 55 | fclose(fp); 56 | 57 | assert(tmp->h_fns->len == g_mem_layout->h_fns->len); 58 | assert(tmp->bank == g_mem_layout->bank); 59 | assert(tmp->row == g_mem_layout->row); 60 | assert(tmp->col == g_mem_layout->col); 61 | 62 | #endif 63 | } 64 | 65 | int main(int argc, char **argv) 66 | { 67 | srand(time(NULL)); 68 | p = (ProfileParams*)malloc(sizeof(ProfileParams)); 69 | if (p == NULL) { 70 | fprintf(stderr, "[ERROR] Memory allocation\n"); 71 | exit(1); 72 | } 73 | 74 | if(process_argv(argc, argv, p) == -1) { 75 | free(p); 76 | exit(1); 77 | } 78 | 79 | MemoryBuffer mem = { 80 | .buffer = NULL, 81 | .physmap = NULL, 82 | .fd = p->huge_fd, 83 | .size = p->m_size, 84 | .align = p->m_align, 85 | .flags = p->g_flags & MEM_MASK 86 | }; 87 | 88 | alloc_buffer(&mem); 89 | set_physmap(&mem); 90 | gmem_dump(); 91 | 92 | SessionConfig s_cfg; 93 | memset(&s_cfg, 0, sizeof(SessionConfig)); 94 | if (p->g_flags & F_CONFIG) { 95 | read_config(&s_cfg, p->conf_file); 96 | } else { 97 | // HARDCODED values 98 | s_cfg.h_rows = PATT_LEN; 99 | s_cfg.h_rounds = p->rounds; 100 | s_cfg.h_cfg = N_SIDED; 101 | s_cfg.d_cfg = RANDOM; 102 | s_cfg.base_off = p->base_off; 103 | s_cfg.aggr_n = p->aggr; 104 | } 105 | 106 | if (p->fuzzing) { 107 | fuzzing_session(&s_cfg, &mem); 108 | } else { 109 | hammer_session(&s_cfg, &mem); 110 | } 111 | 112 | close(p->huge_fd); 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /hammersuite/src/memory.c: -------------------------------------------------------------------------------- 1 | #include "memory.h" 2 | #include "utils.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define DEF_RNG_LEN (8<<10) 16 | #define DEBUG 17 | #define DEBUG_LINE fprintf(stderr, "[DEBUG] - GOT HERE\n"); 18 | 19 | static physaddr_t base_phys = 0L; 20 | 21 | uint64_t get_pfn(uint64_t entry) 22 | { 23 | return ((entry) & 0x7fffffffffffffff); 24 | } 25 | 26 | physaddr_t get_physaddr(uint64_t v_addr, int pmap_fd) 27 | { 28 | uint64_t entry; 29 | uint64_t offset = (v_addr / 4096) * sizeof(entry); 30 | uint64_t pfn; 31 | bool to_open = false; 32 | // assert(fd >= 0); 33 | if (pmap_fd == NOT_OPENED) { 34 | pmap_fd = open("/proc/self/pagemap", O_RDONLY); 35 | assert(pmap_fd >= 0); 36 | to_open = true; 37 | } 38 | // int rd = fread(&entry, sizeof(entry), 1 ,fp); 39 | int bytes_read = pread(pmap_fd, &entry, sizeof(entry), offset); 40 | 41 | assert(bytes_read == 8); 42 | assert(entry & (1ULL << 63)); 43 | 44 | if (to_open) { 45 | close(pmap_fd); 46 | } 47 | 48 | pfn = get_pfn(entry); 49 | assert(pfn != 0); 50 | return (pfn << 12) | (v_addr & 4095); 51 | } 52 | 53 | int phys_cmp(const void *p1, const void *p2) 54 | { 55 | return ((pte_t *) p1)->p_addr - ((pte_t *) p2)->p_addr; 56 | } 57 | 58 | // WARNING optimization works only with contiguous memory!! 59 | void set_physmap(MemoryBuffer * mem) 60 | { 61 | int l_size = mem->size / PAGE_SIZE; 62 | pte_t *physmap = (pte_t *) malloc(sizeof(pte_t) * l_size); 63 | int pmap_fd = open("/proc/self/pagemap", O_RDONLY); 64 | assert(pmap_fd >= 0); 65 | 66 | base_phys = get_physaddr((uint64_t) mem->buffer, pmap_fd); 67 | for (uint64_t tmp = (uint64_t) mem->buffer, idx = 0; 68 | tmp < (uint64_t) mem->buffer + mem->size; tmp += PAGE_SIZE) { 69 | pte_t tmp_pte = { (char *)tmp, get_physaddr(tmp, pmap_fd) }; 70 | physmap[idx] = tmp_pte; 71 | idx++; 72 | } 73 | 74 | qsort(physmap, mem->size / PAGE_SIZE, sizeof(pte_t), phys_cmp); 75 | close(pmap_fd); 76 | mem->physmap = physmap; 77 | } 78 | 79 | physaddr_t virt_2_phys(char *v_addr, MemoryBuffer * mem) 80 | { 81 | for (int i = 0; i < mem->size / PAGE_SIZE; i++) { 82 | if (mem->physmap[i].v_addr == 83 | (char *)((uint64_t) v_addr & ~((uint64_t) (PAGE_SIZE - 1)))) 84 | { 85 | 86 | return mem->physmap[i]. 87 | p_addr | ((uint64_t) v_addr & 88 | ((uint64_t) PAGE_SIZE - 1)); 89 | } 90 | } 91 | return (physaddr_t) NOT_FOUND; 92 | } 93 | 94 | char *phys_2_virt(physaddr_t p_addr, MemoryBuffer * mem) 95 | { 96 | physaddr_t p_page = p_addr & ~(((uint64_t) PAGE_SIZE - 1)); 97 | pte_t src_pte = {.v_addr = 0,.p_addr = p_page }; 98 | pte_t *res_pte = 99 | (pte_t *) bsearch(&src_pte, mem->physmap, mem->size / PAGE_SIZE, 100 | sizeof(pte_t), phys_cmp); 101 | 102 | if (res_pte == NULL) 103 | return (char *)NOT_FOUND; 104 | 105 | return (char *)((uint64_t) res_pte-> 106 | v_addr | ((uint64_t) p_addr & 107 | (((uint64_t) PAGE_SIZE - 1)))); 108 | } 109 | -------------------------------------------------------------------------------- /hammersuite/src/params.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Andrei Tatar 3 | * Copyright (c) 2017-2018 Vrije Universiteit Amsterdam 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | */ 19 | 20 | #include "include/params.h" 21 | #include "include/utils.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | void print_usage(char *bin_name) 33 | { 34 | fprintf(stderr, 35 | "[ HELP ] - Usage ./%s [-h] [-r rounds] [-a aggr] [-o o_file] [-v] [--mem mem_size] [--[huge/HUGE] f_name] [--conf f_name] [--align val] [--off val] [--no-overwrite] [--fuzzing]\n", 36 | bin_name); 37 | fprintf(stderr, "\t-h\t\t\t= this help message\n"); 38 | fprintf(stderr, "\t-v\t\t\t= verbose\n\n"); 39 | fprintf(stderr, "\t-r rounds\t\t= number of rounds per tuple\t\t\t(default: %d)\n", ROUNDS_std); 40 | fprintf(stderr, "\t-a --aggr\t\t= number of aggressors\t\t\t\t(default: %d)\n", AGGR_std); 41 | fprintf(stderr, "\t-o --o_file_prefix\t= prefix for output files\t\t\t(default: %s)\n", O_FILE_std); 42 | fprintf(stderr, "\t--mem mem_size\t\t= allocation size\t\t\t\t(default: %ld)\n", 43 | (uint64_t) ALLOC_SIZE); 44 | fprintf(stderr, "\t--huge f_name\t\t= hugetlbfs entry (1GB if HUGE)\t\t\t(default: %s)\n", 45 | HUGETLB_std); 46 | fprintf(stderr, "\t--conf f_name\t\t= SessionConfig file\t\t\t\t(default: %s)\n", 47 | CONFIG_NAME_std); 48 | fprintf(stderr, "\t--align val\t\t= alignment of the buffer\t\t\t(default: %ld)\n", 49 | (uint64_t) ALIGN_std); 50 | fprintf(stderr, "\t--off val\t\t= offset from first row\t\t\t\t(default: 0)\n"); 51 | fprintf(stderr, "\t--no-overwrite\t\t= don't overwrite previous file\n"); 52 | fprintf(stderr, "\t-V --victim-pattern\t= hex value for the victim patter\n"); 53 | fprintf(stderr, "\t-T --target-pattern\t= hex value for the target pattern\n"); 54 | fprintf(stderr, "\t-f --fuzzing\t\t= Start fuzzing (--aggr will be ignored)\n"); 55 | fprintf(stderr, "\t-t --threshold\t\t= Align the hammering to refresh ops,\n\t\t\t\t looking at the memory latency in CPU cycles.\t(default: 0)\n"); 56 | } 57 | 58 | static int str2pat(const char *str, char **pat) 59 | { 60 | char *endp = NULL; 61 | char tmp[3]; 62 | char *p; 63 | tmp[2] = '\0'; 64 | size_t len = strlen(str); 65 | if (len % 2) { 66 | return EINVAL; 67 | } 68 | len /= 2; 69 | 70 | p = (char *)malloc(len); 71 | for (size_t i = 0; i < len; i++) { 72 | tmp[0] = str[2 * i]; 73 | tmp[1] = str[2 * i + 1]; 74 | errno = 0; 75 | ((uint8_t *) p)[i] = (uint8_t) strtol(tmp, &endp, 16); 76 | if (errno) { 77 | free(p); 78 | return errno; 79 | } 80 | if (*endp != '\0') { 81 | free(p); 82 | return EINVAL; 83 | } 84 | } 85 | *pat = p; 86 | return 0; 87 | } 88 | 89 | int process_argv(int argc, char *argv[], ProfileParams *p) 90 | { 91 | 92 | /* Default */ 93 | p->g_flags = 0; 94 | p->tpat = (char *)NULL; 95 | p->vpat = (char *)NULL; 96 | p->threshold = 0; 97 | p->fuzzing = 0; // start fuzzing!! 98 | p->m_size = ALLOC_SIZE; 99 | p->m_align = ALIGN_std; 100 | p->rounds = ROUNDS_std; 101 | p->base_off = 0; 102 | p->huge_file = (char *)HUGETLB_std; 103 | p->conf_file = (char *)CONFIG_NAME_std; 104 | p->aggr = AGGR_std; 105 | 106 | 107 | const struct option long_options[] = { 108 | /* These options set a flag. */ 109 | {"mem", required_argument, 0, 0}, 110 | {"align", required_argument, 0, 0}, 111 | {"huge", optional_argument, 0, 0}, 112 | {"HUGE", optional_argument, 0, 0}, 113 | {"conf", optional_argument, 0, 0}, 114 | {"off", required_argument, 0, 0}, 115 | {"no-overwrite", no_argument, 0, 0}, 116 | {.name = "target-pattern",.has_arg = required_argument,.flag = NULL,.val='T'}, 117 | {.name = "victim-pattern",.has_arg = required_argument,.flag = NULL,.val = 'V'}, 118 | {.name = "aggr",.has_arg = required_argument,.flag = NULL,.val='a'}, 119 | {.name = "fuzzing",.has_arg = no_argument,.flag = &p->fuzzing,.val = 1}, 120 | {.name = "threshold",.has_arg = required_argument,.flag = NULL,.val = 't'}, 121 | {0, 0, 0, 0} 122 | }; 123 | 124 | p->g_out_prefix = (char *)O_FILE_std; 125 | p->g_flags |= F_POPULATE; 126 | 127 | while (1) { 128 | int this_option_optind = optind ? optind : 1; 129 | int option_index = 0; 130 | int arg = getopt_long(argc, argv, "o:d:r:hvV:T:a:ft:", 131 | long_options, &option_index); 132 | 133 | if (arg == -1) 134 | break; 135 | 136 | switch (arg) { 137 | case 0: 138 | switch (option_index) { 139 | case 0: 140 | p->m_size = atoi(optarg); 141 | break; 142 | case 1: 143 | p->m_align = atoi(optarg); 144 | break; 145 | case 2: 146 | p->g_flags |= F_ALLOC_HUGE_2M; 147 | case 3: 148 | p->huge_file = (char *)malloc(sizeof(char) * strlen(optarg)); 149 | strncpy(p->huge_file, optarg, strlen(optarg)); 150 | p->g_flags |= F_ALLOC_HUGE_1G; 151 | break; 152 | case 4: 153 | p->g_flags |= F_CONFIG; 154 | if (!optarg) 155 | break; 156 | p->conf_file = (char *)malloc(sizeof(char) * strlen(optarg)); 157 | strncpy(p->conf_file, optarg, strlen(optarg)); 158 | break; 159 | case 5: 160 | p->base_off = atoi(optarg); 161 | break; 162 | case 6: 163 | p->g_flags |= F_NO_OVERWRITE; 164 | break; 165 | default: 166 | break; 167 | } 168 | break; 169 | case 'o': 170 | p->g_out_prefix = (char *)malloc(sizeof(char) * strlen(optarg)); 171 | strncpy(p->g_out_prefix, optarg, strlen(optarg)); 172 | p->g_flags |= F_EXPORT; 173 | break; 174 | case 'r': 175 | p->rounds = atoi(optarg); 176 | break; 177 | case 'v': 178 | p->g_flags |= F_VERBOSE; 179 | break; 180 | case 'a': 181 | p->aggr = atoi(optarg); 182 | break; 183 | case 'T': 184 | if (str2pat(optarg, &(p->vpat))) { 185 | fprintf(stderr, "Invalid target fill pattern: %s\n", optarg); 186 | return -1; 187 | } 188 | break; 189 | case 'V': 190 | if (str2pat(optarg, &(p->tpat))) { 191 | fprintf(stderr, "Invalid victim fill pattern: %s\n", optarg); 192 | return -1; 193 | } 194 | break; 195 | case 'f': 196 | p->fuzzing = 1; 197 | break; 198 | case 't': 199 | p->threshold = atoi(optarg); 200 | break; 201 | case 'h': 202 | default: 203 | print_usage(argv[0]); 204 | return -1; 205 | } 206 | } 207 | #ifdef HUGE_YES 208 | p->g_flags |= F_ALLOC_HUGE_1G; 209 | #endif 210 | 211 | if (p->g_flags & (F_ALLOC_HUGE_2M | F_ALLOC_HUGE_1G)) { 212 | if ((p->huge_fd = open(p->huge_file, O_CREAT | O_RDWR, 0755)) == -1) { 213 | perror("[ERROR] - Unable to open hugetlbfs"); 214 | return -1; 215 | } 216 | } 217 | return 0; 218 | } 219 | -------------------------------------------------------------------------------- /hammersuite/src/utils.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 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 | #define PAGE_BITS 12 16 | 17 | #define FLAGS (MAP_PRIVATE | MAP_POPULATE | MAP_HUGETLB | (30<> shift) & 1) { 59 | if (strcmp(bit_str, "") != 0) { 60 | strcat(bit_str, "+ "); 61 | } 62 | sprintf(itoa_str, "%d ", shift); 63 | strcat(bit_str, itoa_str); 64 | } 65 | } 66 | 67 | return bit_str; 68 | } 69 | 70 | char *int_2_bin(uint64_t val) 71 | { 72 | static char bit_str[256]; 73 | char itoa_str[8]; 74 | strcpy(bit_str, "0b"); 75 | for (int shift = 64 - __builtin_clzl(val); shift >= 0; --shift) { 76 | sprintf(itoa_str, "%d", (int)(val >> shift) & 1); 77 | strcat(bit_str, itoa_str); 78 | } 79 | 80 | return bit_str; 81 | } 82 | -------------------------------------------------------------------------------- /py/hammerstats.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: UTF-8 -*- 3 | # Copyright (c) 2016 Andrei Tatar 4 | # Copyright (c) 2018 Vrije Universiteit Amsterdam 5 | # 6 | # This program is licensed under the GPL2+. 7 | 8 | 9 | import sys 10 | 11 | from hammertime import fliptable 12 | 13 | 14 | if __name__ == '__main__': 15 | if len(sys.argv) < 2: 16 | print("Missing arguments") 17 | print("usage: {} PROFILE_PATH [...]".format(sys.argv[0])) 18 | else: 19 | try: 20 | for fn in sys.argv[1:]: 21 | print('Stats for {}:'.format(fn)) 22 | ft = fliptable.Fliptable.load_file(fn) 23 | natks = str(len(ft)) 24 | print('Hammers: {}'.format(natks)) 25 | flips = [len(x.flips) for x in ft if x.flips] 26 | print('w/flips: {{:{}d}}'.format(len(natks)).format(len(flips))) 27 | print('Total Bit Flips: {}'.format(sum(flips))) 28 | except KeyboardInterrupt: 29 | print('Interrupted, exiting...') 30 | -------------------------------------------------------------------------------- /py/hammertime/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: UTF-8 -*- 3 | __all__ = ['sim', 'fliptable', 'dramtrans'] 4 | -------------------------------------------------------------------------------- /py/hammertime/_native.c: -------------------------------------------------------------------------------- 1 | #include "stdint.h" 2 | 3 | uint64_t parity(uint64_t v) { 4 | return __builtin_parityl(v); 5 | } 6 | 7 | 8 | uint64_t ctzl(uint64_t v) { 9 | return __builtin_ctzl(v); 10 | } 11 | -------------------------------------------------------------------------------- /py/hammertime/_native.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vusec/trrespass/7ea523a4149daf1f1c4d8b099c2b3584f973d086/py/hammertime/_native.so -------------------------------------------------------------------------------- /py/hammertime/dramtrans.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import struct 6 | import ctypes 7 | import ctypes.util 8 | import functools 9 | 10 | 11 | HASH_FN_CNT = 6 12 | _native = None 13 | 14 | @functools.total_ordering 15 | class DRAMAddr(ctypes.Structure): 16 | _fields_ = [('bank', ctypes.c_uint64), 17 | ('row', ctypes.c_uint64), 18 | ('col', ctypes.c_uint64)] 19 | 20 | def __str__(self): 21 | return 'b{0.bank:02d}.r{0.row:06d}.c{0.col:04d}'.format(self) 22 | 23 | def __repr__(self): 24 | return self.__str__() 25 | # def __repr__(self): 26 | # return '{0}(b={1.bank},r={1.row},c={1.col})'.format(type(self).__name__, self) 27 | 28 | def __eq__(self, other): 29 | if isinstance(other, DRAMAddr): 30 | return self.numeric_value == other.numeric_value 31 | else: 32 | return NotImplemented 33 | 34 | def __lt__(self, other): 35 | if isinstance(other, DRAMAddr): 36 | return self.numeric_value < other.numeric_value 37 | else: 38 | return NotImplemented 39 | 40 | def __hash__(self): 41 | return self.numeric_value 42 | 43 | def __len__(self): 44 | return len(self._fields_) 45 | 46 | def __getitem__(self, key): 47 | if isinstance(key, int): 48 | return getattr(self, self._fields_[key][0]) 49 | elif isinstance(key, slice): 50 | start, stop, step = key.indices(len(self._fields_)) 51 | return tuple(getattr(self, self._fields_[k][0]) for k in range(start, stop, step)) 52 | else: 53 | raise TypeError('{} object cannot be indexed by {}'.format(type(self).__name__, type(key).__name__)) 54 | 55 | def same_bank(self, other): 56 | return self.bank == other.bank 57 | 58 | @property 59 | def numeric_value(self): 60 | return (self.col + (self.row << 16) + (self.bank << 32)) 61 | 62 | def __add__(self, other): 63 | if isinstance(other, DRAMAddr): 64 | return type(self)( 65 | self.bank + other.bank, 66 | self.row + other.row, 67 | self.col + other.col 68 | ) 69 | else: 70 | return NotImplemented 71 | 72 | def __sub__(self, other): 73 | if isinstance(other, DRAMAddr): 74 | return type(self)( 75 | self.bank - other.bank, 76 | self.row - other.row, 77 | self.col - other.col 78 | ) 79 | else: 80 | return NotImplemented 81 | 82 | 83 | class _AddrFns(ctypes.Structure): 84 | _fields_ = [("lst", ctypes.c_uint64* HASH_FN_CNT), 85 | ("len", ctypes.c_uint64)] 86 | 87 | 88 | class _DRAMLayout(ctypes.Structure): 89 | _fields_ = [("h_fns", _AddrFns), 90 | ("row_mask", ctypes.c_uint64), 91 | ("col_mask", ctypes.c_uint64)] 92 | 93 | def __init__(self, upack): 94 | self.h_fns.lst = (ctypes.c_uint64*6) (*[0x2040,0x44000,0x88000,0x110000,0x220000,0x00]) 95 | self.h_fns.len = 5 96 | self.row_mask = 0xffffc0000 97 | self.col_mask = ((1<<13)-1) 98 | # self.h_fns.lst = upack[0:HASH_FN_CNT] 99 | # self.h_fns.len = upack[HASH_FN_CNT] 100 | # self.row_mask = upack[HASH_FN_CNT+1] 101 | # self.col_mask = upack[HASH_FN_CNT+2] 102 | 103 | @property 104 | def num_banks(self): 105 | return 1<> _native.ctzl(self.row_mask) 109 | 110 | def get_dram_row(self, p_addr): 111 | return (p_addr & self.col_mask) >> _native.ctzl(self.col_mask) 112 | 113 | 114 | class MemorySystem(ctypes.Structure): 115 | _fields_ = [('mem_layout', _DRAMLayout)] 116 | 117 | def __init__(self): 118 | if _native == None: 119 | load_native_funcs() 120 | 121 | return super().__init__() 122 | 123 | def load(self, s): 124 | DRAMLAyout_fmt = f"{HASH_FN_CNT}QQQQ" 125 | self.mem_layout = _DRAMLayout(struct.unpack(DRAMLAyout_fmt, s)) 126 | 127 | def load_file(self, fname): 128 | with open(fname, 'rb') as f: 129 | return self.load(f.read()) 130 | 131 | def num_banks(self): 132 | return self.mem_layout.num_banks 133 | 134 | 135 | def resolve(self, p_addr): 136 | mem = self.mem_layout 137 | d_addr = DRAMAddr(0,0,0) 138 | for i in range(mem.h_fns.len): 139 | d_addr.bank |= (_native.parity(p_addr & mem.h_fns.lst[i]) << i) 140 | d_addr.row = mem.get_dram_row(p_addr) 141 | d_addr.col = mem.get_dram_col(p_addr) 142 | 143 | return d_addr 144 | 145 | 146 | def resolve_reverse(self, d_addr): 147 | mem = self.mem_layout 148 | p_addr = (d_addr.row << _native.ctzl(mem.row_mask)) 149 | p_addr |= (d_addr.col << _native.ctzl(mem.col_mask)) 150 | for i in range(mem.h_fns.len): 151 | masked_addr = p_addr & mem.h_fns.lst[i] 152 | if _native.parity(masked_addr) == ((d_addr.bank >> i) & 1): 153 | continue 154 | # else flip a bit of the address so that the address respects the dram h_fn 155 | # that is get only bits not affecting the row. 156 | h_lsb = _native.ctzl((mem.h_fns.lst[i]) & ~(mem.col_mask) & ~(mem.row_mask)) 157 | p_addr ^= 1<. 18 | 19 | """Module providing utilities for working with profile output and fliptables.""" 20 | 21 | import re 22 | import pprint as pp 23 | 24 | from collections import namedtuple 25 | 26 | from hammertime.dramtrans import DRAMAddr 27 | 28 | RE_DICT = re.compile("(?P[-\d\w]+)\s*:\s*(?P[-.\d\w]+)") 29 | #ADDR_RE = re.compile("r(?P\d+)\.bk(?P\d+)(\.col(?P\d+))?(\.p(?P\d+))?") 30 | ADDR_RE = re.compile("r(?P\d+)\.bk(?P\d+)(\.col(?P\d+))?") 31 | #ADDR_FMT = r'\((\w+)\s+(\w+)\s*(\w+)?\)' 32 | #ADDR_RE = re.compile(ADDR_FMT) 33 | # 87,c7,r16447.bk18.col3994 34 | BFLIP_FMT = r'(?P\w{2}),(?P\w{2}),(?P[.\w\d]+)' 35 | BFLIP_RE = re.compile(BFLIP_FMT) 36 | ADDR_TRG_RE = re.compile("b(?P[\d\w]+)\.r(?P[\d\w]+)") 37 | #VICT_FMT = r'{} (?:{}\s?)+'.format(ADDR_FMT, BFLIP_FMT) 38 | #VICT_RE = re.compile(VICT_FMT) 39 | 40 | 41 | class Corruption(namedtuple('Corruption', ['addr', 'got', 'exp'])): 42 | def __str__(self): 43 | return '({0.addr}|{0.got:02x}|{0.exp:02x})'.format(self) 44 | 45 | def __repr__(self): 46 | return self.__str__() 47 | 48 | def to_flips(self): 49 | flips = [] 50 | pup = ~self.exp & self.got & 0xff 51 | pdn = self.exp & ~self.got & 0xff 52 | bit = 0 53 | while pup: 54 | mask = 1 << bit 55 | if (pup & mask): 56 | flips.append(Flip(self.addr, bit, True)) 57 | pup &= ~mask 58 | bit += 1 59 | bit = 0 60 | while pdn: 61 | mask = 1 << bit 62 | if (pdn & mask): 63 | flips.append(Flip(self.addr, bit, False)) 64 | pdn &= ~mask 65 | bit += 1 66 | return flips 67 | 68 | 69 | class Flip(namedtuple('Flip', ['addr', 'bit', 'pullup'])): 70 | def to_corruption(self, og=None): 71 | fmask = 1 << (self.bit % 8) 72 | if og is None: 73 | pat = 0 if self.pullup else 0xff 74 | else: 75 | pat = og 76 | val = pat | fmask if self.pullup else pat & ~fmask 77 | return Corruption(addr=self.addr, got=val, exp=pat) 78 | 79 | def to_physmem(self, msys): 80 | return type(self)(msys.resolve_reverse(self.addr), self.bit, self.pullup) 81 | 82 | 83 | Diff = namedtuple('Diff', ['self_only', 'common', 'other_only']) 84 | 85 | 86 | class Attack(namedtuple('Attack', ['targets', 'flips'])): 87 | def diff(self, other): 88 | if not isinstance(other, type(self)): 89 | raise TypeError('Attack instance expected for diff') 90 | elif not self.targets == other.targets: 91 | raise ValueError('Cannot diff attacks with different targets') 92 | else: 93 | return Diff( 94 | type(self)(self.targets, self.flips - other.flips), 95 | type(self)(self.targets, self.flips & other.flips), 96 | type(self)(self.targets, other.flips - self.flips) 97 | ) 98 | 99 | def merge(self, other): 100 | if not isinstance(other, type(self)): 101 | raise TypeError('Attack instance expected for merge') 102 | elif not self.targets == other.targets: 103 | raise ValueError('Cannot merge attacks with different targets') 104 | else: 105 | return type(self)(self.targets, self.flips | other.flips) 106 | 107 | def to_corruptions(self, pat=None): 108 | return ((x.addr, x.to_corruption(pat)) for x in self) 109 | 110 | def to_physmem(self, msys): 111 | return type(self)( 112 | targets=tuple(msys.resolve_reverse(x) for x in self.targets), 113 | flips={x.to_physmem(msys) for x in self.flips} 114 | ) 115 | 116 | def __iter__(self): 117 | return iter(sorted(self.flips)) 118 | 119 | @classmethod 120 | def __is_flip_far(cls, targets, victim): 121 | close = False 122 | for t in targets: 123 | if abs(t.row - victim.row) == 1: 124 | close = True 125 | if not close: 126 | print("Found flip far away from target row") 127 | print(targets) 128 | print(victim) 129 | 130 | @classmethod 131 | def decode_line(cls, line, msys=None): 132 | def parse_addr(s): 133 | res = ADDR_RE.match(s) 134 | if res == None: 135 | raise Exception("Couldn't parse") 136 | return DRAMAddr(**({k:int(v) for (k,v) in res.groupdict().items() if v != None})) 137 | 138 | def parse_addr_trg(s): 139 | res = ADDR_TRG_RE.match(s) 140 | if res == None: 141 | raise Exception("Couldn't parse") 142 | return DRAMAddr(**({k:int(v) for (k,v) in res.groupdict().items() if v != None})) 143 | 144 | targ, vict, *o = line.split(':') 145 | flips = set() 146 | targets = [parse_addr(s) for s in line.split('/')] 147 | 148 | for x in BFLIP_RE.finditer(vict): 149 | dct = x.groupdict() 150 | dct['addr'] = parse_addr(dct['addr']) 151 | dct['got'] = int(dct['got'], 16) 152 | dct['exp'] = int(dct['exp'], 16) 153 | cls.__is_flip_far(targets, dct['addr']) 154 | flips.update(Corruption(**(dct)).to_flips()) 155 | 156 | # vaddr = DRAMAddr(*(int(v, 16) for v in x.group(*range(1,4)) if v is not None)) 157 | # vcorr = [Corruption(*(int(v, 16) for v in y.groups())) for y in BFLIP_RE.finditer(x.group(0))] 158 | # for corr in vcorr: 159 | # flips.update(corr.to_flips(vaddr, msys)) 160 | return cls( 161 | targets= targets, 162 | flips=flips 163 | ) 164 | 165 | def encode(self, patterns=None): 166 | if patterns is None: 167 | patterns = [[0xff], [0]] 168 | corrs = [ 169 | [x for x in self.to_corruptions(pat) if x[1].exp != x[1].got] 170 | for pat in patterns 171 | ] 172 | tstr = ' '.join(str(x) for x in self.targets) + ' : ' 173 | return '\n'.join( 174 | tstr + 175 | ' '.join(' '.join(str(x) for x in c) for c in corr) 176 | for corr in corrs 177 | ) 178 | 179 | 180 | def decode_lines(lineiter): 181 | curatk = None 182 | for line in lineiter: 183 | atk = Attack.decode_line(line) 184 | if curatk is None: 185 | curatk = atk 186 | else: 187 | try: 188 | curatk = curatk.merge(atk) 189 | except ValueError: 190 | yield curatk 191 | curatk = atk 192 | if curatk is not None: 193 | yield curatk 194 | 195 | 196 | class Parameters(namedtuple("Parameters", ['h_cfg', 'd_cfg', 'h_rows', 'h_rounds', 'd_base'])): 197 | """""" 198 | @classmethod 199 | def parse_params(cls, string): 200 | matches = RE_DICT.findall(string) 201 | res = {} 202 | for m in matches: 203 | res[m[0]] = m[1] 204 | 205 | return cls(*res.values()) 206 | 207 | 208 | 209 | class Fliptable: 210 | def __init__(self, attacks): 211 | self.attacks=attacks 212 | 213 | def __eq__(self, other): 214 | if isinstance(other, type(self)): 215 | return self.attacks == other.attacks 216 | else: 217 | return NotImplemented 218 | 219 | def __len__(self): 220 | return len(self.attacks) 221 | 222 | def __iter__(self): 223 | return iter(self.attacks) 224 | 225 | def __str__(self): 226 | return '\n'.join(atk.encode() for atk in self) 227 | 228 | def __add__(self, other): 229 | return Fliptable(self.attacks + other.attacks) 230 | 231 | def diff(self, other): 232 | if not isinstance(other, type(self)): 233 | raise ValueError('Fliptable required for diff') 234 | uself = [] 235 | uother = [] 236 | common = [] 237 | 238 | satks = iter(self) 239 | oatks = iter(other) 240 | sa = next(satks, None) 241 | oa = next(oatks, None) 242 | while sa is not None or oa is not None: 243 | # Degenerate cases 244 | if sa is None: 245 | uother.append(oa) 246 | uother.extend(oatks) 247 | break 248 | if oa is None: 249 | uself.append(sa) 250 | uself.extend(satks) 251 | break 252 | try: 253 | adiff = sa.diff(oa) 254 | if adiff.self_only.flips: 255 | uself.append(adiff.self_only) 256 | common.append(adiff.common) 257 | if adiff.other_only.flips: 258 | uother.append(adiff.other_only) 259 | sa = next(satks, None) 260 | oa = next(oatks, None) 261 | except ValueError: 262 | if sa.targets < oa.targets: 263 | uself.append(sa) 264 | sa = next(satks, None) 265 | elif sa.targets > oa.targets: 266 | uother.append(oa) 267 | oa = next(oatks, None) 268 | FT = type(self) 269 | return Diff(FT(uself), FT(common), FT(uother)) 270 | 271 | def to_physmem(self, msys): 272 | return type(self)([x.to_physmem(msys) for x in self]) 273 | 274 | @classmethod 275 | def load_file(cls, fname): 276 | with open(fname, 'r') as f: 277 | # params_line = f.readline().remove("#") # read the first line which contains the parameters of the flip table 278 | # params = Parameters.parse_params(params_line) 279 | # flips = pd.read_csv(f) 280 | # attacks = attacks_generator() 281 | return cls(list(decode_lines(f))) 282 | 283 | def save_file(self, fname): 284 | with open(fname, 'w') as f: 285 | f.write(str(self)) 286 | -------------------------------------------------------------------------------- /py/hammertime/sim.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: UTF-8 -*- 3 | # Copyright (c) 2016 Andrei Tatar 4 | # Copyright (c) 2017-2018 Vrije Universiteit Amsterdam 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | 19 | import math 20 | import itertools 21 | import functools 22 | from collections import namedtuple 23 | 24 | from hammertime import fliptable 25 | from hammertime import dramtrans 26 | import sys 27 | 28 | scan_time = 60000 #ns to scan a row (terrible implementation) 29 | fill_time = 1500 #ns to fill a row 30 | 31 | 32 | class PageBitFlip(namedtuple('PageBitFlip', ['byte_offset', 'mask'])): 33 | """Represents a byte with one or more flipped bits at a particular offset within a page""" 34 | 35 | class VictimPage(namedtuple('VictimPage', ['pfn', 'pullups', 'pulldowns'])): 36 | """Represents the results of one rowhammer attack on one particular physical page""" 37 | 38 | 39 | class ExploitModel: 40 | 41 | def check_page(self, vpage): 42 | raise NotImplementedError() 43 | 44 | def check_attack(self, attack): 45 | for vpage in attack: 46 | if self.check_page(vpage): 47 | yield vpage.pfn 48 | 49 | def check_attacks(self, attacks): 50 | for atk in attacks: 51 | yield tuple(self.check_attack(atk)) 52 | 53 | 54 | def _map_attack(atk, msys, pagesize=0x1000): 55 | pfnof = lambda x: x.addr // pagesize 56 | byteof = lambda x: x.addr % pagesize + x.bit // 8 57 | vict_pages = [] 58 | for pfn, pflips in itertools.groupby(atk.to_physmem(msys), pfnof): 59 | ups = set() 60 | downs = set() 61 | for byte, iflips in itertools.groupby(pflips, byteof): 62 | bflips = list(iflips) 63 | pup = functools.reduce(lambda x,y: x | y, (1 << (x.bit % 8) for x in bflips if x.pullup), 0) 64 | pdn = functools.reduce(lambda x,y: x | y, (1 << (x.bit % 8) for x in bflips if not x.pullup), 0) 65 | if pup: 66 | ups.add(PageBitFlip(byte, pup)) 67 | if pdn: 68 | downs.add(PageBitFlip(byte, pdn)) 69 | if ups or downs: 70 | vict_pages.append(VictimPage(pfn, ups, downs)) 71 | return vict_pages 72 | 73 | 74 | class BaseEstimator: 75 | def __init__(self): 76 | self.clear() 77 | 78 | def iter_attacks(self): 79 | """ 80 | Return an iterator over possible attacks 81 | 82 | An attack consists of a sequence of VictimPages that have bits flipped 83 | as part of a single Rowhammer attack. 84 | """ 85 | raise NotImplementedError() 86 | 87 | def run_exploit(self, model): 88 | self.results = list(model.check_attacks(self.iter_attacks())) 89 | 90 | def clear(self): 91 | self.results = [] 92 | 93 | def print_stats(self): 94 | if self.results: 95 | succ = sum(1 for x in self.results if x) 96 | npages = sum(len(x) for x in self.results if x) 97 | prop = succ / len(self.results) 98 | print('{} total attacks (over {} KiB), of which {} successful ({:5.1f} %)'.format( 99 | len(self.results), len(self.results) * 8, succ, 100.0 * prop 100 | )) 101 | print('{} exploitable pages found'.format(npages)) 102 | if prop != 0: 103 | mna = 1 / prop 104 | print('Minimum (contiguous) memory required: {} KiB'.format(math.ceil(mna) * 8)) 105 | print('Mean number of attacks until successful: {:.1f}'.format(mna)) 106 | print('Mean time to successful attack: {:.1f} seconds (assuming {:.1f}ms/attack)'.format(mna * self.atk_time * 10**-3, self.atk_time)) 107 | 108 | 109 | 110 | class FliptableEstimator(BaseEstimator): 111 | 112 | def __init__(self, fliptbl, memsys, h_time): 113 | self.fliptbl = fliptbl 114 | self.msys = memsys 115 | super().__init__() 116 | self.atk_time = self.compute_atk_time(h_time) 117 | 118 | def iter_attacks(self): 119 | for atk in self.fliptbl: 120 | yield _map_attack(atk, self.msys) 121 | 122 | def compute_atk_time(self, h_time): 123 | n_tgts = len(self.fliptbl.attacks[0].targets) 124 | s_time = scan_time * n_tgts/2 * 3 125 | f_time = fill_time * n_tgts 126 | return (f_time + s_time + h_time) / 10**6 # results in ms 127 | 128 | 129 | @classmethod 130 | def main(cls, profile_file, msys_file, model, h_time): 131 | """Set up an estimator, run an exploit and print out statistics""" 132 | ftbl = fliptable.Fliptable.load_file(profile_file) 133 | msys = dramtrans.MemorySystem() 134 | msys.load_file(msys_file) 135 | est = cls(ftbl, msys, h_time) 136 | est.run_exploit(model) 137 | est.print_stats() 138 | -------------------------------------------------------------------------------- /py/histogram.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import csv 3 | import matplotlib.pyplot as plt 4 | 5 | num_bins = 200 6 | 7 | if __name__ == "__main__": 8 | 9 | if len(sys.argv) != 2: 10 | print("Usage: python histogram.py inputFile") 11 | exit(1) 12 | 13 | csvFile = open(sys.argv[1], "r") 14 | csvFile.readline() # skip first line 15 | 16 | reader = csv.reader(csvFile, delimiter=',') 17 | x = [] 18 | for row in reader: 19 | x.append(int(row[len(row) - 1])) 20 | 21 | print(f'Number of point {len(x)}') 22 | fig, ax = plt.subplots() 23 | n, bins, patches = ax.hist(x, num_bins, density=False) 24 | ax.set_xlabel("Access time [ns]") 25 | ax.set_ylabel("proportion of cases") 26 | plt.show() 27 | --------------------------------------------------------------------------------