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.
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.
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 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.
The library is shipped with a Makefile and can be compiled by running:
make
The necessary header files and the shared and static build library can be installed on the host system:
make install
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.
Additionally we provide an Android.mk
and an Application.mk
file that can be
used to build the library with the Android NDK toolset:
ndk-build NDK_APPLICATION_MK=`pwd`/Application.mk NDK_PROJECT_PATH=`pwd`
libflush does not require any dependencies except for running the test suite. However, by default it uses the toolchains provided by the Android NDK if built for armv7 or armv8.
- Android NDK - Android Native Development Kit (optional, for ARM builds)
- check - Unit Testing Framework for C (optional, for test cases)
- libfiu - Fault injection in userspace (optional, for test cases)
- doxygen (optional, for HTML documentation)
- Sphinx (optional, for HTML documentation)
- sphinx_rtd_theme (optional, for HTML documentation)
- breathe (optional, for HTML documentation)
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:
ARCH
: Defines the target architecture.- x86 (default) - Support for i386 and x86_64
- armv7 - Support for ARMv7
- armv8 - Support for ARMv8
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).DEVICE_CONFIGURATION
: Defines cache and eviction based properties for the target device if eviction is used. See libflush/eviction/strategies for example device configurations.- default (default) - Default device configuration.
- alto45 - Alcatel OneTouch POP 2
- bacon - OnePlus One
- mako - Nexus 4
- hammerhead - Nexus 5
- tilapia - Nexus 7
- manta - Nexus 10
- zeroflte - Samsung Galaxy S6
TIME_SOURCE
: Gives the possibility to use different timing sources to measure the execution time. Depending on the available privileges, one might want to change the timing source.- register - Performance register / Time-stamp counter (default)
- perf - Perf interface
- monotonic_clock - Monotonic clock
- thread_counter - Dedicated thread counter
WITH_PTHREAD
: Build with pthread support.HAVE_PAGEMAP_ACCESS
: Defines if access to /proc/self/pagemap is granted.
If the library is build for the ARMv7 or the ARMv8 architecture the build system uses the config-arm.mk or config-arm64.mk configuration file. By default the build system makes use of the toolchains provided by the Android NDK, thus its possible that the installation path of the NDK needs to be modified:
ANDROID_NDK_PATH
: Path to the installation of the Android NDK.- /opt/android-ndk (default)
ANDROID_PLATFORM
: Defines the used Android platform that is used.- android-21 (default)
If you prefer to use a different toolchain/compiler, feel free to change CC
and other properties accordingly.
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 and is structured as the following:
Cache specific configuration
NUMBER_OF_SETS
: The number of sets in the cacheLINE_LENGTH
: The line lengthLINE_LENGTH_LOG2
: The log base 2 of the line length
Eviction strategy configuration
ES_EVICTION_COUNTER
: Length of the loopES_NUMBER_OF_ACCESSES_IN_LOOP
: Number of accesses of an address in one loop roundES_DIFFERENT_ADDRESSES_IN_LOOP
: Number of different addresses in one loop round
The following sections illustrate the usage of libflush. For a complete overview of the available functions please refer to the source code or to the documentation that can be build.
In order to use libflush one needs to include the header file and call the libflush_init
to initialize
the library. In the end libflush_terminate
needs to be called to clean-up.
#include <libflush.h>
int main(int argc, char* argv[]) {
// Initialize libflush
libflush_session_t* libflush_session;
if (libflush_init(&libflush_session, NULL) == false) {
return -1;
}
// Use libflush...
// Terminate libflush
if (libflush_terminate(libflush_session) == false) {
return -1;
}
return 0;
}
and link against the library:
gcc example.c `pkg-config --libs libflush`
To evict an address from the cache to the main memory, a dedicated flush instruction (if available) or eviction can be used.
void* address = &foo;
// Use the flush instruction (if possible)
libflush_flush(libflush_session, address);
// Use eviction
libflush_evict(libflush_session, address);
To retrieve a time stamp depending on the used time source can be achieved with the following function.
uint64 time = libflush_get_timing(libflush_session);
In addition wrapper functions to measure the execution time of different functions are given.
uint64 time = libflush_reload_address(libflush_session, address);
A more sophisticated example using libflush can be found in the example directory. It implements
a calibration tool for the Flush+Reload, Prime+Probe, Evict+Reload, Flush+Flush and Prefetch attack. The example
can be compiled by running make example
and executed by running ./example/build/<arch>/release/bin/example
. In addition the example can also be build with the ndk-build
tool.
Licensed under the zlib license.