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