0

After long discussion with this Question (Thanks for help!)

Spectre Proof of Concept (PoC) Speculative Execution - Checking for value

Came up with simple PoC based on Spectre paper.

Seems to be consistent, also tried with other character and got similar results.

Execution:

user@laptop:~/labspectre$ ./spectre7
Z should be cached
trying: E time: 96
trying: X time: 93
trying: W time: 93
trying: F time: 93
trying: O time: 93
trying: J time: 93
trying: C time: 93
trying: K time: 93
trying: Y time: 93
trying: T time: 93
trying: D time: 93
trying: M time: 93
trying: L time: 93
trying: P time: 93
trying: Q time: 93
trying: A time: 93
trying: B time: 93
trying: V time: 93
trying: N time: 93
trying: I time: 93
trying: U time: 93
trying: S time: 93
trying: H time: 93
trying: G time: 93
trying: Z time: 8152
trying: R time: 93
user@laptop:~/labspectre$ ./spectre7
Z should be cached
trying: R time: 96
trying: X time: 92
trying: F time: 93
trying: O time: 93
trying: C time: 93
trying: P time: 93
trying: W time: 93
trying: U time: 93
trying: H time: 93
trying: T time: 93
trying: G time: 93
trying: Z time: 259
trying: K time: 93
trying: V time: 93
trying: J time: 93
trying: D time: 96
trying: M time: 93
trying: Q time: 93
trying: L time: 93
trying: E time: 93
trying: B time: 93
trying: S time: 93
trying: A time: 93
trying: Y time: 93
trying: N time: 93
trying: I time: 93
user@laptop:~/labspectre$ ./spectre7
Z should be cached
trying: S time: 97
trying: W time: 93
trying: C time: 93
trying: V time: 93
trying: K time: 93
trying: P time: 93
trying: T time: 93
trying: Y time: 93
trying: A time: 93
trying: U time: 93
trying: N time: 93
trying: D time: 93
trying: O time: 93
trying: J time: 93
trying: R time: 93
trying: M time: 93
trying: F time: 93
trying: Q time: 93
trying: G time: 93
trying: H time: 93
trying: I time: 93
trying: E time: 93
trying: B time: 93
trying: Z time: 230
trying: L time: 93
trying: X time: 93
user@laptop:~/labspectre$ ./spectre7
Z should be cached
trying: B time: 97
trying: A time: 93
trying: P time: 93
trying: I time: 93
trying: M time: 93
trying: E time: 93
trying: W time: 93
trying: H time: 93
trying: V time: 93
trying: D time: 93
trying: N time: 93
trying: Y time: 93
trying: T time: 93
trying: K time: 93
trying: J time: 93
trying: X time: 93
trying: R time: 93
trying: S time: 93
trying: L time: 93
trying: U time: 93
trying: G time: 93
trying: C time: 93
trying: Z time: 328
trying: O time: 93
trying: Q time: 93
trying: F time: 93
user@laptop:~/labspectre$ ./spectre7
Z should be cached
trying: B time: 97
trying: G time: 93
trying: O time: 93
trying: X time: 93
trying: N time: 93
trying: F time: 93
trying: A time: 93
trying: Q time: 93
trying: Y time: 93
trying: M time: 93
trying: S time: 93
trying: K time: 93
trying: I time: 93
trying: W time: 93
trying: J time: 93
trying: R time: 93
trying: C time: 93
trying: V time: 93
trying: L time: 93
trying: Z time: 272
trying: P time: 93
trying: U time: 93
trying: H time: 92
trying: T time: 93
trying: E time: 93
trying: D time: 93
user@laptop:~/labspectre$ ./spectre7
Z should be cached
trying: R time: 97
trying: A time: 95
trying: M time: 153
trying: F time: 95
trying: H time: 93
trying: L time: 93
trying: D time: 92
trying: G time: 93
trying: K time: 93
trying: U time: 93
trying: S time: 93
trying: W time: 93
trying: O time: 97
trying: Y time: 93
trying: Z time: 289
trying: C time: 93
trying: P time: 93
trying: Q time: 100
trying: B time: 92
trying: J time: 92
trying: I time: 92
trying: V time: 95
trying: E time: 93
trying: X time: 93
trying: T time: 93
trying: N time: 93
user@laptop:~/labspectre$ ./spectre7
Z should be cached
trying: P time: 98
trying: I time: 93
trying: F time: 93
trying: L time: 93
trying: W time: 93
trying: D time: 93
trying: V time: 93
trying: S time: 93
trying: H time: 93
trying: J time: 93
trying: K time: 93
trying: M time: 93
trying: O time: 93
trying: A time: 93
trying: Z time: 363
trying: X time: 93
trying: C time: 93
trying: Y time: 93
trying: E time: 93
trying: Q time: 93
trying: B time: 93
trying: R time: 93
trying: N time: 93
trying: T time: 93
trying: U time: 93
trying: G time: 93

Sample Spectre PoC

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef _MSC_VER
#include <intrin.h> /* for rdtscp and clflush */
#pragma optimize("gt",on)
#else
#include <x86intrin.h> /* for rdtscp and clflush */
#endif




void main(void)
{
volatile uint8_t array1[26] = { 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90 };

uint8_t array2[256 * 512];

for(int i = 0; i < sizeof(array2); i++)
  array2[i] = 1; /* write to array2 so in RAM not copy-on-write zero pages */


for(int i = 0; i < 256; i++)
  _mm_clflush(&array2[i * 512]); /* intrinsic for clflush instruction */



printf("%c should be cached\n", array1[25]);

int dummy = 0;
for(int i=0; i<26; i++) {
 if (i != 25) {
    array2[array1[i] * 512] = array1[i]; 
 }
}



int t0,time_taken = 0;
int junk = 0;

int mix_i=0;

 int i,j;
    int aux,res;

    char RandomId[26];
    char ListId[26]={65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90};



    srand(time(NULL));

    for(i=0; i<26; i++)
    {
        res = rand() % 26;
        aux = ListId[res];

        if (ListId[res] != -1)
        {
            RandomId[i] = aux;
            ListId[res] = -1;
        }
        else
            i--;
    }



volatile uint8_t * addr;
int y=0;


  for(int i=0; i<26; i++)
  {
    mix_i = RandomId[i];
    addr = &array2[mix_i * 512];
    t0 = __rdtscp(&junk); 
    junk = *addr;
    time_taken = __rdtscp(&junk) - t0;
    if(mix_i>=65 && mix_i<=90)
    printf("trying: %c time: %i\n",mix_i,time_taken);
  }
}

My big question is however:

Whats wrong with it? Where is my error?

Since it is showing HIGHER access times for cached (speculatively loaded) values?

I am running AMD A10-5757M processor.

dev
  • 937
  • 1
  • 8
  • 23

1 Answers1

2

You flush the array out of the cache here -

for(int i = 0; i < 256; i++)
  _mm_clflush(&array2[i * 512]); /* intrinsic for clflush instruction */

Then you pull it back into the cache

for(int i=0; i<26; i++) {
  if (i != 25) {
    array2[array1[i] * 512] = array1[i]; 
  }
}

This suggests for i == 25 the if branch is not taken (i.e. not speculatively executed). Every other page in the array is cached but the page referenced by 'Z' isn't.

As I said in your previous question you really need to understand how the proof of concept you are trying to replicate works before you will get anywhere.

As for why there is no speculative execution there are a number of possibilities. For example you haven't attempted to heavily train the branch. Its also possible either the compiler or processor is optimizing out the != 25 and just reducing the "i < 26" statement.

Hector
  • 10,893
  • 3
  • 41
  • 44
  • Thanks! As always, great answer. Will work on it further – dev Jan 18 '18 at 09:20
  • FYI I think I "pulled" it off - https://0bin.net/paste/UwXD3IrXahYoMV+j#gGy2u26yrlSff-uclqU65HBA5cGJPYPDgada4idsCta "a" was loaded speculatively. Do you agree? It seems like ca. 100 cycles is cached, and ca. 300 not cached. – dev Jan 18 '18 at 11:59
  • Why would A be loaded speculatively? A is 65 right? Which is array1[0]. Line 73 will pull that into cache on the first iteration. – Hector Jan 18 '18 at 12:10
  • You're right. I was wrong. Well I tried to load lowercase "a" speculatively - decimal 97. And prove than 1 is not in the cache .... https://0bin.net/paste/71KyAi6l9zIYqPKh#kCUXyIgeRTZh3NRNpGPNQaMWJiMXzqmfWAQkwZDvLp3 But you're right ... it wasnt loaded speculatively. I guess I guess to train the branch, empirically was thinking that increasing the loop interation count will do it ... will have to read how to do this. I disabled compiler optimizations, so hopefully this is not the problem. – dev Jan 18 '18 at 12:20
  • Opened another question for this: https://security.stackexchange.com/questions/177900/spectre-code-optimization-branch-training-concept (If you or anybody else than you is interested in followup) – dev Jan 18 '18 at 12:46