summaryrefslogtreecommitdiff
path: root/src/crypto/test/abi_test.h
blob: a3c4bb872c679325f45900e8f2babdf5ff4446b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
/* Copyright (c) 2018, Google Inc.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */

#ifndef OPENSSL_HEADER_ABI_TEST_H
#define OPENSSL_HEADER_ABI_TEST_H

#include <gtest/gtest.h>

#include <string>
#include <type_traits>
#include <vector>

#include <openssl/base.h>

#include "../internal.h"


// abi_test provides routines for verifying that functions satisfy platform ABI
// requirements.
namespace abi_test {

// Result stores the result of an ABI test.
struct Result {
  bool ok() const { return errors.empty(); }

  std::vector<std::string> errors;
};

namespace internal {

// DeductionGuard wraps |T| in a template, so that template argument deduction
// does not apply to it. This may be used to force C++ to deduce template
// arguments from another parameter.
template <typename T>
struct DeductionGuard {
  using Type = T;
};

// Reg128 contains storage space for a 128-bit register.
struct alignas(16) Reg128 {
  bool operator==(const Reg128 &x) const { return x.lo == lo && x.hi == hi; }
  bool operator!=(const Reg128 &x) const { return !((*this) == x); }
  uint64_t lo, hi;
};

// LOOP_CALLER_STATE_REGISTERS is a macro that iterates over all registers the
// callee is expected to save for the caller, with the exception of the stack
// pointer. The stack pointer is tested implicitly by the function successfully
// returning at all.
#if defined(OPENSSL_X86_64)

// References:
// SysV64: https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf
// Win64: https://docs.microsoft.com/en-us/cpp/build/x64-software-conventions?view=vs-2017#register-usage
#if defined(OPENSSL_WINDOWS)
#define LOOP_CALLER_STATE_REGISTERS()  \
  CALLER_STATE_REGISTER(uint64_t, rbx) \
  CALLER_STATE_REGISTER(uint64_t, rbp) \
  CALLER_STATE_REGISTER(uint64_t, rdi) \
  CALLER_STATE_REGISTER(uint64_t, rsi) \
  CALLER_STATE_REGISTER(uint64_t, r12) \
  CALLER_STATE_REGISTER(uint64_t, r13) \
  CALLER_STATE_REGISTER(uint64_t, r14) \
  CALLER_STATE_REGISTER(uint64_t, r15) \
  CALLER_STATE_REGISTER(Reg128, xmm6)  \
  CALLER_STATE_REGISTER(Reg128, xmm7)  \
  CALLER_STATE_REGISTER(Reg128, xmm8)  \
  CALLER_STATE_REGISTER(Reg128, xmm9)  \
  CALLER_STATE_REGISTER(Reg128, xmm10) \
  CALLER_STATE_REGISTER(Reg128, xmm11) \
  CALLER_STATE_REGISTER(Reg128, xmm12) \
  CALLER_STATE_REGISTER(Reg128, xmm13) \
  CALLER_STATE_REGISTER(Reg128, xmm14) \
  CALLER_STATE_REGISTER(Reg128, xmm15)
#else
#define LOOP_CALLER_STATE_REGISTERS()  \
  CALLER_STATE_REGISTER(uint64_t, rbx) \
  CALLER_STATE_REGISTER(uint64_t, rbp) \
  CALLER_STATE_REGISTER(uint64_t, r12) \
  CALLER_STATE_REGISTER(uint64_t, r13) \
  CALLER_STATE_REGISTER(uint64_t, r14) \
  CALLER_STATE_REGISTER(uint64_t, r15)
#endif  // OPENSSL_WINDOWS

#elif defined(OPENSSL_X86)

// References:
// SysV32: https://uclibc.org/docs/psABI-i386.pdf and
// Win32: https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions?view=vs-2017
#define LOOP_CALLER_STATE_REGISTERS()  \
  CALLER_STATE_REGISTER(uint32_t, esi) \
  CALLER_STATE_REGISTER(uint32_t, edi) \
  CALLER_STATE_REGISTER(uint32_t, ebx) \
  CALLER_STATE_REGISTER(uint32_t, ebp)

#elif defined(OPENSSL_ARM)

// References:
// AAPCS: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf
// iOS32: https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html
// Linux: http://sourcery.mentor.com/sgpp/lite/arm/portal/kbattach142/arm_gnu_linux_%20abi.pdf
//
// ARM specifies a common calling convention, except r9 is left to the platform.
// Linux treats r9 as callee-saved, while iOS 3+ treats it as caller-saved. Most
// of our assembly treats it as callee-saved to be uniform, but we match the
// platform to avoid false positives when testing compiler-generated output.
#define LOOP_CALLER_STATE_REGISTERS_PRE_R9() \
  CALLER_STATE_REGISTER(uint64_t, d8)        \
  CALLER_STATE_REGISTER(uint64_t, d9)        \
  CALLER_STATE_REGISTER(uint64_t, d10)       \
  CALLER_STATE_REGISTER(uint64_t, d11)       \
  CALLER_STATE_REGISTER(uint64_t, d12)       \
  CALLER_STATE_REGISTER(uint64_t, d13)       \
  CALLER_STATE_REGISTER(uint64_t, d14)       \
  CALLER_STATE_REGISTER(uint64_t, d15)       \
  CALLER_STATE_REGISTER(uint32_t, r4)        \
  CALLER_STATE_REGISTER(uint32_t, r5)        \
  CALLER_STATE_REGISTER(uint32_t, r6)        \
  CALLER_STATE_REGISTER(uint32_t, r7)        \
  CALLER_STATE_REGISTER(uint32_t, r8)
#define LOOP_CALLER_STATE_REGISTERS_POST_R9() \
  CALLER_STATE_REGISTER(uint32_t, r10)        \
  CALLER_STATE_REGISTER(uint32_t, r11)
#if defined(OPENSSL_APPLE)
#define LOOP_CALLER_STATE_REGISTERS()  \
  LOOP_CALLER_STATE_REGISTERS_PRE_R9() \
  LOOP_CALLER_STATE_REGISTERS_POST_R9()
#else  // !OPENSSL_APPLE
#define LOOP_CALLER_STATE_REGISTERS()  \
  LOOP_CALLER_STATE_REGISTERS_PRE_R9() \
  CALLER_STATE_REGISTER(uint32_t, r9)  \
  LOOP_CALLER_STATE_REGISTERS_POST_R9()
#endif  // OPENSSL_APPLE

#elif defined(OPENSSL_AARCH64)

// References:
// AAPCS64: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
// iOS64: https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html
//
// In aarch64, r18 (accessed as w18 or x18 in a 64-bit context) is the platform
// register. iOS says user code may not touch it. We found no clear reference
// for Linux. The iOS behavior implies portable assembly cannot use it, and
// aarch64 has many registers. Thus this framework ignores register's existence.
// We test r18 violations in arm-xlate.pl.
#define LOOP_CALLER_STATE_REGISTERS()                                \
  /* Per AAPCS64, section 5.1.2, only the bottom 64 bits of v8-v15 */ \
  /* are preserved. These are accessed as dN. */                     \
  CALLER_STATE_REGISTER(uint64_t, d8)                                \
  CALLER_STATE_REGISTER(uint64_t, d9)                                \
  CALLER_STATE_REGISTER(uint64_t, d10)                               \
  CALLER_STATE_REGISTER(uint64_t, d11)                               \
  CALLER_STATE_REGISTER(uint64_t, d12)                               \
  CALLER_STATE_REGISTER(uint64_t, d13)                               \
  CALLER_STATE_REGISTER(uint64_t, d14)                               \
  CALLER_STATE_REGISTER(uint64_t, d15)                               \
  /* For consistency with dN, use the 64-bit name xN, rather than */ \
  /* the generic rN. */                                              \
  CALLER_STATE_REGISTER(uint64_t, x19)                               \
  CALLER_STATE_REGISTER(uint64_t, x20)                               \
  CALLER_STATE_REGISTER(uint64_t, x21)                               \
  CALLER_STATE_REGISTER(uint64_t, x22)                               \
  CALLER_STATE_REGISTER(uint64_t, x23)                               \
  CALLER_STATE_REGISTER(uint64_t, x24)                               \
  CALLER_STATE_REGISTER(uint64_t, x25)                               \
  CALLER_STATE_REGISTER(uint64_t, x26)                               \
  CALLER_STATE_REGISTER(uint64_t, x27)                               \
  CALLER_STATE_REGISTER(uint64_t, x28)                               \
  CALLER_STATE_REGISTER(uint64_t, x29)

#endif  // X86_64 || X86 || ARM || AARCH64

// Enable ABI testing if all of the following are true.
//
// - We have CallerState and trampoline support for the architecture.
//
// - Assembly is enabled.
//
// - This is not a shared library build. Assembly functions are not reachable
//   from tests in shared library builds.
#if defined(LOOP_CALLER_STATE_REGISTERS) && !defined(OPENSSL_NO_ASM) && \
    !defined(BORINGSSL_SHARED_LIBRARY)
#define SUPPORTS_ABI_TEST

// CallerState contains all caller state that the callee is expected to
// preserve.
struct CallerState {
#define CALLER_STATE_REGISTER(type, name) type name;
  LOOP_CALLER_STATE_REGISTERS()
#undef CALLER_STATE_REGISTER
};

// RunTrampoline runs |func| on |argv|, recording ABI errors in |out|. It does
// not perform any type-checking. If |unwind| is true and unwind tests have been
// enabled, |func| is single-stepped under an unwind test.
crypto_word_t RunTrampoline(Result *out, crypto_word_t func,
                            const crypto_word_t *argv, size_t argc,
                            bool unwind);

template <typename T>
inline crypto_word_t ToWord(T t) {
#if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) && \
    !defined(OPENSSL_ARM) && !defined(OPENSSL_AARCH64)
#error "Unknown architecture"
#endif
  static_assert(sizeof(T) <= sizeof(crypto_word_t),
                "T is larger than crypto_word_t");
  static_assert(sizeof(T) >= 4, "types under four bytes are complicated");

  // ABIs are complex around arguments that are smaller than native words. For
  // 32-bit architectures, the rules above imply we only have word-sized
  // arguments. For 64-bit architectures, we still have assembly functions which
  // take |int|.
  //
  // For aarch64, AAPCS64, section 5.4.2, clauses C.7 and C.14 says any
  // remaining bits are unspecified. iOS64 contradicts this and says the callee
  // extends arguments up to 32 bits, and only the upper 32 bits are
  // unspecified. Rejecting parameters smaller than 32 bits avoids the
  // divergence.
  //
  // TODO(davidben): Find authoritative citations for x86_64. For x86_64, I
  // observed the behavior of Clang, GCC, and MSVC. ABI rules here may be
  // inferred from two kinds of experiments:
  //
  // 1. When passing a value to a small-argument-taking function, does the
  //    compiler ensure unused bits are cleared, sign-extended, etc.? Tests for
  //    register parameters are confounded by x86_64's implicit clearing of
  //    registers' upper halves, but passing some_u64 >> 1 usually clears this.
  //
  // 2. When compiling a small-argument-taking function, does the compiler make
  //    assumptions about unused bits of arguments?
  //
  // MSVC for x86_64 is straightforward. It appears to tolerate and produce
  // arbitrary values for unused bits, like AAPCS64.
  //
  // GCC and Clang for x86_64 are more complex. They match MSVC for stack
  // parameters. However, for register parameters, they behave like iOS64 and,
  // as callers, extend up to 32 bits, leaving the remainder arbitrary. When
  // compiling a callee, Clang takes advantage of this conversion, but I was
  // unable to make GCC do so.
  //
  // Note that, although the Win64 rules are sufficient to require our assembly
  // be conservative, we wish for |CHECK_ABI| to support C-compiled functions,
  // so it must enforce the correct rules for each platform.
  //
  // Fortunately, the |static_assert|s above cause all supported architectures
  // to behave the same.
  crypto_word_t ret;
  // Filling extra bits with 0xaa will be vastly out of bounds for code
  // expecting either sign- or zero-extension. (0xaa is 0b10101010.)
  OPENSSL_memset(&ret, 0xaa, sizeof(ret));
  OPENSSL_memcpy(&ret, &t, sizeof(t));
  return ret;
}

// CheckImpl runs |func| on |args|, recording ABI errors in |out|. If |unwind|
// is true and unwind tests have been enabled, |func| is single-stepped under an
// unwind test.
//
// It returns the value as a |crypto_word_t| to work around problems when |R| is
// void. |args| is wrapped in a |DeductionGuard| so |func| determines the
// template arguments. Otherwise, |args| may deduce |Args| incorrectly. For
// instance, if |func| takes const int *, and the caller passes an int *, the
// compiler will complain the deduced types do not match.
template <typename R, typename... Args>
inline crypto_word_t CheckImpl(Result *out, bool unwind, R (*func)(Args...),
                               typename DeductionGuard<Args>::Type... args) {
  // We only support up to 8 arguments. This ensures all arguments on aarch64
  // are passed in registers and avoids the iOS descrepancy around packing small
  // arguments on the stack.
  //
  // https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html
  static_assert(sizeof...(args) <= 8,
                "too many arguments for abi_test_trampoline");

  // Allocate one extra entry so MSVC does not complain about zero-size arrays.
  crypto_word_t argv[sizeof...(args) + 1] = {
      ToWord(args)...,
  };
  return RunTrampoline(out, reinterpret_cast<crypto_word_t>(func), argv,
                       sizeof...(args), unwind);
}
#else
// To simplify callers when ABI testing support is unavoidable, provide a backup
// CheckImpl implementation. It must be specialized for void returns because we
// call |func| directly.
template <typename R, typename... Args>
inline typename std::enable_if<!std::is_void<R>::value, crypto_word_t>::type
CheckImpl(Result *out, bool /* unwind */, R (*func)(Args...),
          typename DeductionGuard<Args>::Type... args) {
  *out = Result();
  return func(args...);
}

template <typename... Args>
inline crypto_word_t CheckImpl(Result *out, bool /* unwind */,
                               void (*func)(Args...),
                               typename DeductionGuard<Args>::Type... args) {
  *out = Result();
  func(args...);
  return 0;
}
#endif  // SUPPORTS_ABI_TEST

// FixVAArgsString takes a string like "f, 1, 2" and returns a string like
// "f(1, 2)".
//
// This is needed because the |CHECK_ABI| macro below cannot be defined as
// CHECK_ABI(func, ...). The C specification requires that variadic macros bind
// at least one variadic argument. Clang, GCC, and MSVC all ignore this, but
// there are issues with trailing commas and different behaviors across
// compilers.
std::string FixVAArgsString(const char *str);

// CheckGTest behaves like |CheckImpl|, but it returns the correct type and
// raises GTest assertions on failure. If |unwind| is true and unwind tests are
// enabled, |func| is single-stepped under an unwind test.
template <typename R, typename... Args>
inline R CheckGTest(const char *va_args_str, const char *file, int line,
                    bool unwind, R (*func)(Args...),
                    typename DeductionGuard<Args>::Type... args) {
  Result result;
  crypto_word_t ret = CheckImpl(&result, unwind, func, args...);
  if (!result.ok()) {
    testing::Message msg;
    msg << "ABI failures in " << FixVAArgsString(va_args_str) << ":\n";
    for (const auto &error : result.errors) {
      msg << "    " << error << "\n";
    }
    ADD_FAILURE_AT(file, line) << msg;
  }
  return (R)ret;
}

}  // namespace internal

// Check runs |func| on |args| and returns the result. If ABI-testing is
// supported in this build configuration, it writes any ABI failures to |out|.
// Otherwise, it runs the function transparently.
template <typename R, typename... Args>
inline R Check(Result *out, R (*func)(Args...),
               typename internal::DeductionGuard<Args>::Type... args) {
  return (R)internal::CheckImpl(out, false, func, args...);
}

// EnableUnwindTests enables unwind tests, if supported. If not supported, it
// does nothing.
void EnableUnwindTests();

// UnwindTestsEnabled returns true if unwind tests are enabled and false
// otherwise.
bool UnwindTestsEnabled();

}  // namespace abi_test

// CHECK_ABI calls the first argument on the remaining arguments and returns the
// result. If ABI-testing is supported in this build configuration, it adds a
// non-fatal GTest failure if the call did not satisfy ABI requirements.
//
// |CHECK_ABI| does return the value and thus may replace any function call,
// provided it takes only simple parameters. However, it is recommended to test
// ABI separately from functional tests of assembly. Fully instrumenting a
// function for ABI checking requires single-stepping the function, which is
// inefficient.
//
// Functional testing requires coverage of input values, while ABI testing only
// requires branch coverage. Most of our assembly is constant-time, so usually
// only a few instrumented calls are necessary.
//
// TODO(https://crbug.com/boringssl/259): Most of Windows assembly currently
// fails SEH testing. For now, |CHECK_ABI| behaves like |CHECK_ABI_NO_UNWIND|
// on Windows. Functions which work with unwind testing on Windows should use
// |CHECK_ABI_SEH|.
#if defined(OPENSSL_WINDOWS)
#define CHECK_ABI(...) CHECK_ABI_NO_UNWIND(__VA_ARGS__)
#else
#define CHECK_ABI(...) CHECK_ABI_SEH(__VA_ARGS__)
#endif

// CHECK_ABI_SEH behaves like |CHECK_ABI| but enables unwind testing on Windows.
#define CHECK_ABI_SEH(...)                                               \
  abi_test::internal::CheckGTest(#__VA_ARGS__, __FILE__, __LINE__, true, \
                                 __VA_ARGS__)

// CHECK_ABI_NO_UNWIND behaves like |CHECK_ABI| but disables unwind testing.
#define CHECK_ABI_NO_UNWIND(...)                                          \
  abi_test::internal::CheckGTest(#__VA_ARGS__, __FILE__, __LINE__, false, \
                                 __VA_ARGS__)


// Internal functions.

#if defined(SUPPORTS_ABI_TEST)
struct Uncallable {
  Uncallable() = delete;
};

extern "C" {

// abi_test_trampoline loads callee-saved registers from |state|, calls |func|
// with |argv|, then saves the callee-saved registers into |state|. It returns
// the result of |func|. If |unwind| is non-zero, this function triggers unwind
// instrumentation.
//
// We give |func| type |crypto_word_t| to avoid tripping MSVC's warning 4191.
crypto_word_t abi_test_trampoline(crypto_word_t func,
                                  abi_test::internal::CallerState *state,
                                  const crypto_word_t *argv, size_t argc,
                                  crypto_word_t unwind);

#if defined(OPENSSL_X86_64)
// abi_test_unwind_start points at the instruction that starts unwind testing in
// |abi_test_trampoline|. This is the value of the instruction pointer at the
// first |SIGTRAP| during unwind testing.
//
// This symbol is not a function and should not be called.
void abi_test_unwind_start(Uncallable);

// abi_test_unwind_return points at the instruction immediately after the call in
// |abi_test_trampoline|. When unwinding the function under test, this is the
// expected address in the |abi_test_trampoline| frame. After this address, the
// unwind tester should ignore |SIGTRAP| until |abi_test_unwind_stop|.
//
// This symbol is not a function and should not be called.
void abi_test_unwind_return(Uncallable);

// abi_test_unwind_stop is the value of the instruction pointer at the final
// |SIGTRAP| during unwind testing.
//
// This symbol is not a function and should not be called.
void abi_test_unwind_stop(Uncallable);

// abi_test_bad_unwind_wrong_register preserves the ABI, but annotates the wrong
// register in unwind metadata.
void abi_test_bad_unwind_wrong_register(void);

// abi_test_bad_unwind_temporary preserves the ABI, but temporarily corrupts the
// storage space for a saved register, breaking unwind.
void abi_test_bad_unwind_temporary(void);

#if defined(OPENSSL_WINDOWS)
// abi_test_bad_unwind_epilog preserves the ABI, and correctly annotates the
// prolog, but the epilog does not match Win64's rules, breaking unwind during
// the epilog.
void abi_test_bad_unwind_epilog(void);
#endif
#endif  // OPENSSL_X86_64

#if defined(OPENSSL_X86_64) || defined(OPENSSL_X86)
// abi_test_get_and_clear_direction_flag clears the direction flag. If the flag
// was previously set, it returns one. Otherwise, it returns zero.
int abi_test_get_and_clear_direction_flag(void);

// abi_test_set_direction_flag sets the direction flag. This does not conform to
// ABI requirements and must only be called within a |CHECK_ABI| guard to avoid
// errors later in the program.
int abi_test_set_direction_flag(void);
#endif  // OPENSSL_X86_64 || OPENSSL_X86

}  // extern "C"
#endif  // SUPPORTS_ABI_TEST


#endif  // OPENSSL_HEADER_ABI_TEST_H