blob: f08dc57360b0a9faa588472386f5d94f72b1aa75 [file] [log] [blame] [edit]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIBBRILLO_BRILLO_SECURE_STRING_H_
#define LIBBRILLO_BRILLO_SECURE_STRING_H_
#include <cstddef>
#include <memory>
#include <type_traits>
#include <base/check.h>
#include <brillo/asan.h>
#include <brillo/brillo_export.h>
namespace brillo {
// An implementation of the proposed "secure_clear" standard:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1315r5.html.
//
// This function is guaranteed to fill in the whole buffer
// and is not subject to compiler optimization as allowed by Sub-clause 5.1.2.3
// of C Standard [ISO/IEC 9899:2011] which states:
// In the abstract machine, all expressions are evaluated as specified by the
// semantics. An actual implementation need not evaluate part of an expression
// if it can deduce that its value is not used and that no needed side effects
// are produced (including any caused by calling a function or accessing
// a volatile object).
// While memset() can be optimized out in certain situations (since most
// compilers implement this function as intrinsic and know of its side effects),
// this function will not be optimized out.
//
// SecureClearBytes is used to write beyond the size() in several functions.
// Since this is intentional, disable address sanitizer from analyzing it.
BRILLO_EXPORT BRILLO_DISABLE_ASAN void SecureClearBytes(void* v, size_t n);
// Variant of SecureClearBytes that works with contiguous containers (vector,
// array, etc.), strings, and c-style arrays.
template <typename C>
BRILLO_EXPORT void SecureClearContainer(C& v) { // NOLINT(runtime/references)
using T = std::remove_reference_t<decltype(*std::data(v))>;
static_assert(std::is_trivially_destructible_v<T>,
"Element type of the container must be trivially destructible");
SecureClearBytes(std::data(v), std::size(v) * sizeof(T));
}
// Variant of SecureClearBytes that works with generic (trivially destructible)
// objects, including scalar objects such as "int", "int*", etc.
template <typename T>
BRILLO_EXPORT void SecureClearObject(T& v) { // NOLINT(runtime/references)
static_assert(!std::is_pointer_v<T>,
"Pass the object to be cleared, not a pointer");
static_assert(!std::is_array_v<T>, "Use SecureClearContainer for arrays");
static_assert(std::is_trivially_destructible_v<T>,
"Object must be trivially destructible");
SecureClearBytes(std::addressof(v), sizeof(v));
}
// Compare [n] bytes starting at [s1] with [s2] and return 0 if they match,
// 1 if they don't. Time taken to perform the comparison is only dependent on
// [n] and not on the relationship of the match between [s1] and [s2].
// When n == 0, returns 0 (same as memcmp).
BRILLO_EXPORT int SecureMemcmp(const void* s1, const void* s2, size_t n);
} // namespace brillo
#endif // LIBBRILLO_BRILLO_SECURE_STRING_H_