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