ソースを参照

ct: use inline static instead of macros

blog/frodo_constant_time_issue
Henry Case 3年前
コミット
55719e929c
2個のファイルの変更56行の追加55行の削除
  1. +44
    -38
      src/common/ct_check.h
  2. +12
    -17
      test/ct.cpp

+ 44
- 38
src/common/ct_check.h ファイルの表示

@@ -1,49 +1,55 @@
#ifndef CT_CHECK_H
#define CT_CHECK_H

// helper
#define VOID(V) ((void)V)

// Uses Clang's Memory Sanitizer
#if defined(PQC_USE_CTSANITIZER)
#if defined(__clang__) && defined(__has_feature) && __has_feature(memory_sanitizer)
#if defined(PQC_USE_CTSANITIZER) && defined(__clang__) && defined(__has_feature) && __has_feature(memory_sanitizer)
#include <stddef.h>
#include <sanitizer/msan_interface.h>
// Set sz bytes of memory starting at x as uninitialized. Switches on
// constat time checks.
#define CT_DYE(x,sz) __msan_allocated_memory(x,sz)
// Set sz bytes of memory starting at x as initialized. Switches off
// constat time checks.
#define CT_PURIFY(x, sz) __msan_unpoison(x, sz)
// This macro is useful for testing. It instructs memory sanitizer
// that code expects to do reads from unintialized memory.
#define CT_EXPECT_UMR() __msan_set_expect_umr(1)
// This macro works in tandem with CT_EXPECT_UMR. It checks if
// unintialized memory read has occured, if not, it will report
// an error. In current version, code needs to be compiled
// with `-mllvm -msan-keep-going=1` flags in order to work
// correctly (otherwise, runtime will be stopped between
// macros with message "Existing").
#define CT_REQUIRE_UMR() __msan_set_expect_umr(0)
#else
#error("Clang is required to use CT_SANITIZER.")
#endif
// Uses Valgrind's Memcheck (aka ctgrind)
#elif defined(PQC_USE_CTGRIND)
#include <valgrind/valgrind.h>
#include <valgrind/memcheck.h>
// Set sz bytes of memory starting at x as uninitialized. Switches on
// constat time checks.
#define CT_DYE(p,sz) VALGRIND_MAKE_MEM_UNDEFINED(p,sz)
// Set sz bytes of memory starting at x as initialized. Switches off
// constat time checks.
#define CT_PURIFY(p,sz) VALGRIND_MAKE_MEM_DEFINED(p,sz)
// Not supported in Valgrind
#define CT_EXPECT_UMR()
// Not supported in Valgrind
#define CT_REQUIRE_UMR()
#endif

// Set sz bytes of memory starting at address p as uninitialized. Switches on constat time checks.
static inline void ct_poison(const volatile void *p, size_t sz) {
#if defined(PQC_USE_CTSANITIZER) && defined(__clang__) && defined(__has_feature) && __has_feature(memory_sanitizer)
__msan_allocated_memory(p,sz);
#elif defined(PQC_USE_CTGRIND)
VALGRIND_MAKE_MEM_UNDEFINED(p,sz);
#else
VOID(p), VOID(sz);
#endif
}

#elif // no ct-checks
#define CT_DYE(x,sz)
#define CT_PURIFY(x, sz)
#define CT_EXPECT_UMR()
#define CT_REQUIRE_UMR()
#endif // defined(__clang__) && defined(__has_feature) && __has_feature(memory_sanitizer)
// Set sz bytes of memory starting at p as initialized. Switches off constat time checks.
static inline void ct_purify(const volatile void *p, size_t sz) {
#if defined(PQC_USE_CTSANITIZER) && defined(__clang__) && defined(__has_feature) && __has_feature(memory_sanitizer)
__msan_unpoison(p,sz);
#elif defined(PQC_USE_CTGRIND)
VALGRIND_MAKE_MEM_DEFINED(p,sz);
#else
VOID(p), VOID(sz);
#endif
}

// Function instructs memory sanitizer that code expects to do operation on unintialized memory.
static inline void ct_expect_umr() {
#if defined(PQC_USE_CTSANITIZER) && defined(__clang__) && defined(__has_feature) && __has_feature(memory_sanitizer)
__msan_set_expect_umr(1);
#endif
}

// Checks if action on unintialized memory has occured. If this is not a case
// then error is reported. It works in tandem with ct_expect_umr(). In current version of
// MSan, the code needs to be compiled with `-mllvm -msan-keep-going=1` flags in order to work
// correctly.
static inline void ct_require_umr() {
#if defined(PQC_USE_CTSANITIZER) && defined(__clang__) && defined(__has_feature) && __has_feature(memory_sanitizer)
__msan_set_expect_umr(0);
#endif
}

#endif // CT_CHECK_H

+ 12
- 17
test/ct.cpp ファイルの表示

@@ -3,11 +3,6 @@
#include <gtest/gtest.h>
#include <common/ct_check.h>
#include <stdio.h>
// tests from https://github.com/agl/ctgrind/blob/master/test.c

void nothing(void) {
printf("exiting...");
}

TEST(ConstantTime, CtGrind_Negative) {
unsigned char a[16], b[16];
@@ -15,16 +10,16 @@ TEST(ConstantTime, CtGrind_Negative) {
memset(a, 42, 16);
memset(b, 42, 16);

CT_DYE(a, 16);
ct_poison(a, 16);
for (i = 0; i < 16; i++) {
CT_EXPECT_UMR();
ct_expect_umr();
if (a[i] != b[i]) {
break;
}
CT_REQUIRE_UMR();
ct_require_umr();
}

CT_PURIFY(a, 16);
ct_purify(a, 16);
// Ensure buffers are not optimized-out
ASSERT_EQ(a[0], b[0]);
}
@@ -36,16 +31,16 @@ TEST(ConstantTime, CtGrind_Positive_NoAccess) {
memset(a, 42, sizeof(a));
memset(b, 42, sizeof(b));

CT_DYE(a, 16);
ct_poison(a, 16);

for (i = 0; i < 16; i++) {
result |= a[i] ^ b[i];
}
CT_PURIFY(a, 16);
ct_purify(a, 16);

// Purify result, to allow check that otherwise
// would be not constant-time.
CT_PURIFY(&result, 1);
ct_purify(&result, 1);
ASSERT_EQ(result, 0);
}

@@ -56,15 +51,15 @@ TEST(ConstantTime, CtGrind_Negative_UseSecretAsIndex) {
unsigned char result;
memset(a, 42, sizeof(a));

CT_DYE(a, 16);
ct_poison(a, 16);

CT_EXPECT_UMR();
ct_expect_umr();
result = tab[a[0] & 1];
CT_REQUIRE_UMR();
ct_require_umr();

CT_PURIFY(a, 16);
ct_purify(a, 16);

// Ensure variables are not optimized-out
CT_PURIFY(&result, 1);
ct_purify(&result, 1);
ASSERT_EQ(result, 1);
}

読み込み中…
キャンセル
保存