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 static uint32_t CRYPTO_BUFFER_hash(const CRYPTO_BUFFER *buf) { 30 return OPENSSL_hash32(buf->data, buf->len); 31 } 32 33 static int CRYPTO_BUFFER_cmp(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b) { 34 if (a->len != b->len) { 35 return 1; 36 } 37 return OPENSSL_memcmp(a->data, b->data, a->len); 38 } 39 40 CRYPTO_BUFFER_POOL* CRYPTO_BUFFER_POOL_new(void) { 41 CRYPTO_BUFFER_POOL *pool = OPENSSL_malloc(sizeof(CRYPTO_BUFFER_POOL)); 42 if (pool == NULL) { 43 return NULL; 44 } 45 46 OPENSSL_memset(pool, 0, sizeof(CRYPTO_BUFFER_POOL)); 47 pool->bufs = lh_CRYPTO_BUFFER_new(CRYPTO_BUFFER_hash, CRYPTO_BUFFER_cmp); 48 if (pool->bufs == NULL) { 49 OPENSSL_free(pool); 50 return NULL; 51 } 52 53 CRYPTO_MUTEX_init(&pool->lock); 54 55 return pool; 56 } 57 58 void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool) { 59 if (pool == NULL) { 60 return; 61 } 62 63 #if !defined(NDEBUG) 64 CRYPTO_MUTEX_lock_write(&pool->lock); 65 assert(lh_CRYPTO_BUFFER_num_items(pool->bufs) == 0); 66 CRYPTO_MUTEX_unlock_write(&pool->lock); 67 #endif 68 69 lh_CRYPTO_BUFFER_free(pool->bufs); 70 CRYPTO_MUTEX_cleanup(&pool->lock); 71 OPENSSL_free(pool); 72 } 73 74 CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len, 75 CRYPTO_BUFFER_POOL *pool) { 76 if (pool != NULL) { 77 CRYPTO_BUFFER tmp; 78 tmp.data = (uint8_t *) data; 79 tmp.len = len; 80 81 CRYPTO_MUTEX_lock_read(&pool->lock); 82 CRYPTO_BUFFER *const duplicate = 83 lh_CRYPTO_BUFFER_retrieve(pool->bufs, &tmp); 84 if (duplicate != NULL) { 85 CRYPTO_refcount_inc(&duplicate->references); 86 } 87 CRYPTO_MUTEX_unlock_read(&pool->lock); 88 89 if (duplicate != NULL) { 90 return duplicate; 91 } 92 } 93 94 CRYPTO_BUFFER *const buf = OPENSSL_malloc(sizeof(CRYPTO_BUFFER)); 95 if (buf == NULL) { 96 return NULL; 97 } 98 OPENSSL_memset(buf, 0, sizeof(CRYPTO_BUFFER)); 99 100 buf->data = BUF_memdup(data, len); 101 if (len != 0 && buf->data == NULL) { 102 OPENSSL_free(buf); 103 return NULL; 104 } 105 106 buf->len = len; 107 buf->references = 1; 108 109 if (pool == NULL) { 110 return buf; 111 } 112 113 buf->pool = pool; 114 115 CRYPTO_MUTEX_lock_write(&pool->lock); 116 CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, buf); 117 int inserted = 0; 118 if (duplicate == NULL) { 119 CRYPTO_BUFFER *old = NULL; 120 inserted = lh_CRYPTO_BUFFER_insert(pool->bufs, &old, buf); 121 assert(old == NULL); 122 } else { 123 CRYPTO_refcount_inc(&duplicate->references); 124 } 125 CRYPTO_MUTEX_unlock_write(&pool->lock); 126 127 if (!inserted) { 128 /* We raced to insert |buf| into the pool and lost, or else there was an 129 * error inserting. */ 130 OPENSSL_free(buf->data); 131 OPENSSL_free(buf); 132 return duplicate; 133 } 134 135 return buf; 136 } 137 138 CRYPTO_BUFFER* CRYPTO_BUFFER_new_from_CBS(CBS *cbs, CRYPTO_BUFFER_POOL *pool) { 139 return CRYPTO_BUFFER_new(CBS_data(cbs), CBS_len(cbs), pool); 140 } 141 142 void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf) { 143 if (buf == NULL) { 144 return; 145 } 146 147 CRYPTO_BUFFER_POOL *const pool = buf->pool; 148 if (pool == NULL) { 149 if (CRYPTO_refcount_dec_and_test_zero(&buf->references)) { 150 /* If a reference count of zero is observed, there cannot be a reference 151 * from any pool to this buffer and thus we are able to free this 152 * buffer. */ 153 OPENSSL_free(buf->data); 154 OPENSSL_free(buf); 155 } 156 157 return; 158 } 159 160 CRYPTO_MUTEX_lock_write(&pool->lock); 161 if (!CRYPTO_refcount_dec_and_test_zero(&buf->references)) { 162 CRYPTO_MUTEX_unlock_write(&buf->pool->lock); 163 return; 164 } 165 166 /* We have an exclusive lock on the pool, therefore no concurrent lookups can 167 * find this buffer and increment the reference count. Thus, if the count is 168 * zero there are and can never be any more references and thus we can free 169 * this buffer. */ 170 void *found = lh_CRYPTO_BUFFER_delete(pool->bufs, buf); 171 assert(found != NULL); 172 assert(found == buf); 173 (void)found; 174 CRYPTO_MUTEX_unlock_write(&buf->pool->lock); 175 OPENSSL_free(buf->data); 176 OPENSSL_free(buf); 177 } 178 179 int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf) { 180 /* This is safe in the case that |buf->pool| is NULL because it's just 181 * standard reference counting in that case. 182 * 183 * This is also safe if |buf->pool| is non-NULL because, if it were racing 184 * with |CRYPTO_BUFFER_free| then the two callers must have independent 185 * references already and so the reference count will never hit zero. */ 186 CRYPTO_refcount_inc(&buf->references); 187 return 1; 188 } 189 190 const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf) { 191 return buf->data; 192 } 193 194 size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf) { 195 return buf->len; 196 } 197 198 void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out) { 199 CBS_init(out, buf->data, buf->len); 200 } 201