xref: /aosp_15_r20/system/keymaster/include/keymaster/mem.h (revision 789431f29546679ab5188a97751fb38e3018d44d)
1 /*
2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 namespace keymaster {
20 
21 /*
22  * Array Manipulation functions.  This set of templated inline functions provides some nice tools
23  * for operating on c-style arrays.  C-style arrays actually do have a defined size associated with
24  * them, as long as they are not allowed to decay to a pointer.  These template methods exploit this
25  * to allow size-based array operations without explicitly specifying the size.  If passed a pointer
26  * rather than an array, they'll fail to compile.
27  */
28 
29 /**
30  * Return the size in bytes of the array \p a.
31  */
array_size(const T (& a)[N])32 template <typename T, size_t N> inline size_t array_size(const T (&a)[N]) {
33     return sizeof(a);
34 }
35 
36 /**
37  * Return the number of elements in array \p a.
38  */
array_length(const T (&)[N])39 template <typename T, size_t N> inline size_t array_length(const T (&)[N]) {
40     return N;
41 }
42 
43 /**
44  * Duplicate the array \p a.  The memory for the new array is allocated and the caller takes
45  * responsibility.
46  */
dup_array(const T * a,size_t n)47 template <typename T> inline T* dup_array(const T* a, size_t n) {
48     T* dup = new (std::nothrow) T[n];
49     if (dup)
50         for (size_t i = 0; i < n; ++i)
51             dup[i] = a[i];
52     return dup;
53 }
54 
55 /**
56  * Duplicate the array \p a.  The memory for the new array is allocated and the caller takes
57  * responsibility.  Note that the dup is necessarily returned as a pointer, so size is lost.  Call
58  * array_length() on the original array to discover the size.
59  */
dup_array(const T (& a)[N])60 template <typename T, size_t N> inline T* dup_array(const T (&a)[N]) {
61     return dup_array(a, N);
62 }
63 
64 /**
65  * Duplicate the buffer \p buf.  The memory for the new buffer is allocated and the caller takes
66  * responsibility.
67  */
68 uint8_t* dup_buffer(const void* buf, size_t size);
69 
70 /**
71  * Copy the contents of array \p arr to \p dest.
72  */
copy_array(const T (& arr)[N],T * dest)73 template <typename T, size_t N> inline void copy_array(const T (&arr)[N], T* dest) {
74     for (size_t i = 0; i < N; ++i)
75         dest[i] = arr[i];
76 }
77 
78 /**
79  * Search array \p a for value \p val, returning true if found.  Note that this function is
80  * early-exit, meaning that it should not be used in contexts where timing analysis attacks could be
81  * a concern.
82  */
array_contains(const T (& a)[N],T val)83 template <typename T, size_t N> inline bool array_contains(const T (&a)[N], T val) {
84     for (size_t i = 0; i < N; ++i) {
85         if (a[i] == val) {
86             return true;
87         }
88     }
89     return false;
90 }
91 
92 /**
93  * Variant of memset() that uses GCC-specific pragmas to disable optimizations, so effect is not
94  * optimized away.  This is important because we often need to wipe blocks of sensitive data from
95  * memory.  As an additional convenience, this implementation avoids writing to NULL pointers.
96  */
97 #ifdef __clang__
98 #define OPTNONE __attribute__((optnone))
99 #else  // not __clang__
100 #define OPTNONE __attribute__((optimize("O0")))
101 #endif  // not __clang__
memset_s(void * s,int c,size_t n)102 inline OPTNONE void* memset_s(void* s, int c, size_t n) {
103     if (!s) return s;
104     return memset(s, c, n);
105 }
106 #undef OPTNONE
107 
108 /**
109  * Variant of memcmp that has the same runtime regardless of whether the data matches (i.e. doesn't
110  * short-circuit).  Not an exact equivalent to memcmp because it doesn't return <0 if p1 < p2, just
111  * 0 for match and non-zero for non-match.
112  */
113 int memcmp_s(const void* p1, const void* p2, size_t length);
114 
115 /**
116  * Eraser clears buffers.  Construct it with a buffer or object and the destructor will ensure that
117  * it is zeroed.
118  */
119 class Eraser {
120   public:
121     /* Not implemented.  If this gets used, we want a link error. */
122     template <typename T> explicit Eraser(T* t);
123 
124     template <typename T>
Eraser(T & t)125     explicit Eraser(T& t) : buf_(reinterpret_cast<uint8_t*>(&t)), size_(sizeof(t)) {}
126 
Eraser(uint8_t (& arr)[N])127     template <size_t N> explicit Eraser(uint8_t (&arr)[N]) : buf_(arr), size_(N) {}
128 
Eraser(void * buf,size_t size)129     Eraser(void* buf, size_t size) : buf_(static_cast<uint8_t*>(buf)), size_(size) {}
~Eraser()130     ~Eraser() { memset_s(buf_, 0, size_); }
131 
132   private:
133     Eraser(const Eraser&);
134     void operator=(const Eraser&);
135 
136     uint8_t* buf_;
137     size_t size_;
138 };
139 
140 /**
141  * ArrayWrapper is a trivial wrapper around a C-style array that provides begin() and end()
142  * methods. This is primarily to facilitate range-based iteration on arrays.  It does not copy, nor
143  * does it take ownership; it just holds pointers.
144  */
145 template <typename T> class ArrayWrapper {
146   public:
ArrayWrapper(T * array,size_t size)147     ArrayWrapper(T* array, size_t size) : begin_(array), end_(array + size) {}
148 
begin()149     T* begin() { return begin_; }
end()150     T* end() { return end_; }
151 
152   private:
153     T* begin_;
154     T* end_;
155 };
156 
array_range(T * begin,size_t length)157 template <typename T> ArrayWrapper<T> array_range(T* begin, size_t length) {
158     return ArrayWrapper<T>(begin, length);
159 }
160 
array_range(T (& a)[n])161 template <typename T, size_t n> ArrayWrapper<T> array_range(T (&a)[n]) {
162     return ArrayWrapper<T>(a, n);
163 }
164 
165 struct Malloc_Delete {
operatorMalloc_Delete166     void operator()(void* p) { free(p); }
167 };
168 
169 }  // namespace keymaster
170