• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DEFINE_LHASH_OF(CRYPTO_BUFFER)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 
CRYPTO_BUFFER_cmp(const CRYPTO_BUFFER * a,const CRYPTO_BUFFER * b)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 
CRYPTO_BUFFER_POOL_new(void)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 
CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL * pool)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 
CRYPTO_BUFFER_new(const uint8_t * data,size_t len,CRYPTO_BUFFER_POOL * pool)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 
CRYPTO_BUFFER_alloc(uint8_t ** out_data,size_t len)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 
CRYPTO_BUFFER_new_from_CBS(CBS * cbs,CRYPTO_BUFFER_POOL * pool)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 
CRYPTO_BUFFER_free(CRYPTO_BUFFER * buf)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 
CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER * buf)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 
CRYPTO_BUFFER_data(const CRYPTO_BUFFER * buf)211 const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf) {
212   return buf->data;
213 }
214 
CRYPTO_BUFFER_len(const CRYPTO_BUFFER * buf)215 size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf) {
216   return buf->len;
217 }
218 
CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER * buf,CBS * out)219 void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out) {
220   CBS_init(out, buf->data, buf->len);
221 }
222