1 | /* Copyright (c) 2016, Google Inc. |
2 | * |
3 | * Permission to use, copy, modify, and/or distribute this software for any |
4 | * purpose with or without fee is hereby granted, provided that the above |
5 | * copyright notice and this permission notice appear in all copies. |
6 | * |
7 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
10 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
14 | |
15 | #include <openssl/pool.h> |
16 | |
17 | #include <assert.h> |
18 | #include <string.h> |
19 | |
20 | #include <openssl/buf.h> |
21 | #include <openssl/bytestring.h> |
22 | #include <openssl/mem.h> |
23 | #include <openssl/thread.h> |
24 | |
25 | #include "../internal.h" |
26 | #include "internal.h" |
27 | |
28 | |
29 | DEFINE_LHASH_OF(CRYPTO_BUFFER) |
30 | |
31 | static uint32_t CRYPTO_BUFFER_hash(const CRYPTO_BUFFER *buf) { |
32 | return OPENSSL_hash32(buf->data, buf->len); |
33 | } |
34 | |
35 | static int CRYPTO_BUFFER_cmp(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b) { |
36 | if (a->len != b->len) { |
37 | return 1; |
38 | } |
39 | return OPENSSL_memcmp(a->data, b->data, a->len); |
40 | } |
41 | |
42 | CRYPTO_BUFFER_POOL* CRYPTO_BUFFER_POOL_new(void) { |
43 | CRYPTO_BUFFER_POOL *pool = OPENSSL_malloc(sizeof(CRYPTO_BUFFER_POOL)); |
44 | if (pool == NULL) { |
45 | return NULL; |
46 | } |
47 | |
48 | OPENSSL_memset(pool, 0, sizeof(CRYPTO_BUFFER_POOL)); |
49 | pool->bufs = lh_CRYPTO_BUFFER_new(CRYPTO_BUFFER_hash, CRYPTO_BUFFER_cmp); |
50 | if (pool->bufs == NULL) { |
51 | OPENSSL_free(pool); |
52 | return NULL; |
53 | } |
54 | |
55 | CRYPTO_MUTEX_init(&pool->lock); |
56 | |
57 | return pool; |
58 | } |
59 | |
60 | void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool) { |
61 | if (pool == NULL) { |
62 | return; |
63 | } |
64 | |
65 | #if !defined(NDEBUG) |
66 | CRYPTO_MUTEX_lock_write(&pool->lock); |
67 | assert(lh_CRYPTO_BUFFER_num_items(pool->bufs) == 0); |
68 | CRYPTO_MUTEX_unlock_write(&pool->lock); |
69 | #endif |
70 | |
71 | lh_CRYPTO_BUFFER_free(pool->bufs); |
72 | CRYPTO_MUTEX_cleanup(&pool->lock); |
73 | OPENSSL_free(pool); |
74 | } |
75 | |
76 | CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len, |
77 | CRYPTO_BUFFER_POOL *pool) { |
78 | if (pool != NULL) { |
79 | CRYPTO_BUFFER tmp; |
80 | tmp.data = (uint8_t *) data; |
81 | tmp.len = len; |
82 | |
83 | CRYPTO_MUTEX_lock_read(&pool->lock); |
84 | CRYPTO_BUFFER *const duplicate = |
85 | lh_CRYPTO_BUFFER_retrieve(pool->bufs, &tmp); |
86 | if (duplicate != NULL) { |
87 | CRYPTO_refcount_inc(&duplicate->references); |
88 | } |
89 | CRYPTO_MUTEX_unlock_read(&pool->lock); |
90 | |
91 | if (duplicate != NULL) { |
92 | return duplicate; |
93 | } |
94 | } |
95 | |
96 | CRYPTO_BUFFER *const buf = OPENSSL_malloc(sizeof(CRYPTO_BUFFER)); |
97 | if (buf == NULL) { |
98 | return NULL; |
99 | } |
100 | OPENSSL_memset(buf, 0, sizeof(CRYPTO_BUFFER)); |
101 | |
102 | buf->data = BUF_memdup(data, len); |
103 | if (len != 0 && buf->data == NULL) { |
104 | OPENSSL_free(buf); |
105 | return NULL; |
106 | } |
107 | |
108 | buf->len = len; |
109 | buf->references = 1; |
110 | |
111 | if (pool == NULL) { |
112 | return buf; |
113 | } |
114 | |
115 | buf->pool = pool; |
116 | |
117 | CRYPTO_MUTEX_lock_write(&pool->lock); |
118 | CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, buf); |
119 | int inserted = 0; |
120 | if (duplicate == NULL) { |
121 | CRYPTO_BUFFER *old = NULL; |
122 | inserted = lh_CRYPTO_BUFFER_insert(pool->bufs, &old, buf); |
123 | assert(old == NULL); |
124 | } else { |
125 | CRYPTO_refcount_inc(&duplicate->references); |
126 | } |
127 | CRYPTO_MUTEX_unlock_write(&pool->lock); |
128 | |
129 | if (!inserted) { |
130 | // We raced to insert |buf| into the pool and lost, or else there was an |
131 | // error inserting. |
132 | OPENSSL_free(buf->data); |
133 | OPENSSL_free(buf); |
134 | return duplicate; |
135 | } |
136 | |
137 | return buf; |
138 | } |
139 | |
140 | CRYPTO_BUFFER *CRYPTO_BUFFER_alloc(uint8_t **out_data, size_t len) { |
141 | CRYPTO_BUFFER *const buf = OPENSSL_malloc(sizeof(CRYPTO_BUFFER)); |
142 | if (buf == NULL) { |
143 | return NULL; |
144 | } |
145 | OPENSSL_memset(buf, 0, sizeof(CRYPTO_BUFFER)); |
146 | |
147 | buf->data = OPENSSL_malloc(len); |
148 | if (len != 0 && buf->data == NULL) { |
149 | OPENSSL_free(buf); |
150 | return NULL; |
151 | } |
152 | buf->len = len; |
153 | buf->references = 1; |
154 | |
155 | *out_data = buf->data; |
156 | return buf; |
157 | } |
158 | |
159 | CRYPTO_BUFFER* CRYPTO_BUFFER_new_from_CBS(CBS *cbs, CRYPTO_BUFFER_POOL *pool) { |
160 | return CRYPTO_BUFFER_new(CBS_data(cbs), CBS_len(cbs), pool); |
161 | } |
162 | |
163 | void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf) { |
164 | if (buf == NULL) { |
165 | return; |
166 | } |
167 | |
168 | CRYPTO_BUFFER_POOL *const pool = buf->pool; |
169 | if (pool == NULL) { |
170 | if (CRYPTO_refcount_dec_and_test_zero(&buf->references)) { |
171 | // If a reference count of zero is observed, there cannot be a reference |
172 | // from any pool to this buffer and thus we are able to free this |
173 | // buffer. |
174 | OPENSSL_free(buf->data); |
175 | OPENSSL_free(buf); |
176 | } |
177 | |
178 | return; |
179 | } |
180 | |
181 | CRYPTO_MUTEX_lock_write(&pool->lock); |
182 | if (!CRYPTO_refcount_dec_and_test_zero(&buf->references)) { |
183 | CRYPTO_MUTEX_unlock_write(&buf->pool->lock); |
184 | return; |
185 | } |
186 | |
187 | // We have an exclusive lock on the pool, therefore no concurrent lookups can |
188 | // find this buffer and increment the reference count. Thus, if the count is |
189 | // zero there are and can never be any more references and thus we can free |
190 | // this buffer. |
191 | void *found = lh_CRYPTO_BUFFER_delete(pool->bufs, buf); |
192 | assert(found != NULL); |
193 | assert(found == buf); |
194 | (void)found; |
195 | CRYPTO_MUTEX_unlock_write(&buf->pool->lock); |
196 | OPENSSL_free(buf->data); |
197 | OPENSSL_free(buf); |
198 | } |
199 | |
200 | int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf) { |
201 | // This is safe in the case that |buf->pool| is NULL because it's just |
202 | // standard reference counting in that case. |
203 | // |
204 | // This is also safe if |buf->pool| is non-NULL because, if it were racing |
205 | // with |CRYPTO_BUFFER_free| then the two callers must have independent |
206 | // references already and so the reference count will never hit zero. |
207 | CRYPTO_refcount_inc(&buf->references); |
208 | return 1; |
209 | } |
210 | |
211 | const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf) { |
212 | return buf->data; |
213 | } |
214 | |
215 | size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf) { |
216 | return buf->len; |
217 | } |
218 | |
219 | void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out) { |
220 | CBS_init(out, buf->data, buf->len); |
221 | } |
222 | |