]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/geom/eli/g_eli_key_cache.c
Import tzdata 2018d
[FreeBSD/FreeBSD.git] / sys / geom / eli / g_eli_key_cache.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #ifdef _KERNEL
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/sysctl.h>
37 #include <sys/systm.h>
38 #endif /* _KERNEL */
39 #include <sys/queue.h>
40 #include <sys/tree.h>
41
42 #include <geom/geom.h>
43
44 #include <geom/eli/g_eli.h>
45
46 #ifdef _KERNEL
47 MALLOC_DECLARE(M_ELI);
48
49 SYSCTL_DECL(_kern_geom_eli);
50 /*
51  * The default limit (8192 keys) will allow to cache all keys for 4TB
52  * provider with 512 bytes sectors and will take around 1MB of memory.
53  */
54 static u_int g_eli_key_cache_limit = 8192;
55 SYSCTL_UINT(_kern_geom_eli, OID_AUTO, key_cache_limit, CTLFLAG_RDTUN,
56     &g_eli_key_cache_limit, 0, "Maximum number of encryption keys to cache");
57 static uint64_t g_eli_key_cache_hits;
58 SYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_hits, CTLFLAG_RW,
59     &g_eli_key_cache_hits, 0, "Key cache hits");
60 static uint64_t g_eli_key_cache_misses;
61 SYSCTL_UQUAD(_kern_geom_eli, OID_AUTO, key_cache_misses, CTLFLAG_RW,
62     &g_eli_key_cache_misses, 0, "Key cache misses");
63
64 #endif /* _KERNEL */
65
66 static int
67 g_eli_key_cmp(const struct g_eli_key *a, const struct g_eli_key *b)
68 {
69
70         if (a->gek_keyno > b->gek_keyno)
71                 return (1);
72         else if (a->gek_keyno < b->gek_keyno)
73                 return (-1);
74         return (0);
75 }
76
77 void
78 g_eli_key_fill(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno)
79 {
80         const uint8_t *ekey;
81         struct {
82                 char magic[4];
83                 uint8_t keyno[8];
84         } __packed hmacdata;
85
86         if ((sc->sc_flags & G_ELI_FLAG_ENC_IVKEY) != 0)
87                 ekey = sc->sc_mkey;
88         else
89                 ekey = sc->sc_ekey;
90
91         bcopy("ekey", hmacdata.magic, 4);
92         le64enc(hmacdata.keyno, keyno);
93         g_eli_crypto_hmac(ekey, G_ELI_MAXKEYLEN, (uint8_t *)&hmacdata,
94             sizeof(hmacdata), key->gek_key, 0);
95         key->gek_keyno = keyno;
96         key->gek_count = 0;
97         key->gek_magic = G_ELI_KEY_MAGIC;
98 }
99
100 #ifdef _KERNEL
101 RB_PROTOTYPE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp);
102 RB_GENERATE(g_eli_key_tree, g_eli_key, gek_link, g_eli_key_cmp);
103
104 static struct g_eli_key *
105 g_eli_key_allocate(struct g_eli_softc *sc, uint64_t keyno)
106 {
107         struct g_eli_key *key, *ekey, keysearch;
108
109         mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
110         mtx_unlock(&sc->sc_ekeys_lock);
111
112         key = malloc(sizeof(*key), M_ELI, M_WAITOK);
113         g_eli_key_fill(sc, key, keyno);
114
115         mtx_lock(&sc->sc_ekeys_lock);
116         /*
117          * Recheck if the key wasn't added while we weren't holding the lock.
118          */
119         keysearch.gek_keyno = keyno;
120         ekey = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch);
121         if (ekey != NULL) {
122                 explicit_bzero(key, sizeof(*key));
123                 free(key, M_ELI);
124                 key = ekey;
125                 TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
126         } else {
127                 RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key);
128                 sc->sc_ekeys_allocated++;
129         }
130         TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next);
131
132         return (key);
133 }
134
135 static struct g_eli_key *
136 g_eli_key_find_last(struct g_eli_softc *sc)
137 {
138         struct g_eli_key *key;
139
140         mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
141
142         TAILQ_FOREACH(key, &sc->sc_ekeys_queue, gek_next) {
143                 if (key->gek_count == 0)
144                         break;
145         }
146
147         return (key);
148 }
149
150 static void
151 g_eli_key_replace(struct g_eli_softc *sc, struct g_eli_key *key, uint64_t keyno)
152 {
153
154         mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
155         KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid magic."));
156
157         RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key);
158         TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
159
160         KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count));
161
162         g_eli_key_fill(sc, key, keyno);
163
164         RB_INSERT(g_eli_key_tree, &sc->sc_ekeys_tree, key);
165         TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next);
166 }
167
168 static void
169 g_eli_key_remove(struct g_eli_softc *sc, struct g_eli_key *key)
170 {
171
172         mtx_assert(&sc->sc_ekeys_lock, MA_OWNED);
173         KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid magic."));
174         KASSERT(key->gek_count == 0, ("gek_count=%d", key->gek_count));
175
176         RB_REMOVE(g_eli_key_tree, &sc->sc_ekeys_tree, key);
177         TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
178         sc->sc_ekeys_allocated--;
179         explicit_bzero(key, sizeof(*key));
180         free(key, M_ELI);
181 }
182
183 void
184 g_eli_key_init(struct g_eli_softc *sc)
185 {
186         uint8_t *mkey;
187
188         mtx_lock(&sc->sc_ekeys_lock);
189
190         mkey = sc->sc_mkey + sizeof(sc->sc_ivkey);
191         if ((sc->sc_flags & G_ELI_FLAG_AUTH) == 0)
192                 bcopy(mkey, sc->sc_ekey, G_ELI_DATAKEYLEN);
193         else {
194                 /*
195                  * The encryption key is: ekey = HMAC_SHA512(Data-Key, 0x10)
196                  */
197                 g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1,
198                     sc->sc_ekey, 0);
199         }
200
201         if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) {
202                 sc->sc_ekeys_total = 1;
203                 sc->sc_ekeys_allocated = 0;
204         } else {
205                 off_t mediasize;
206                 size_t blocksize;
207
208                 if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) {
209                         struct g_provider *pp;
210
211                         pp = LIST_FIRST(&sc->sc_geom->consumer)->provider;
212                         mediasize = pp->mediasize;
213                         blocksize = pp->sectorsize;
214                 } else {
215                         mediasize = sc->sc_mediasize;
216                         blocksize = sc->sc_sectorsize;
217                 }
218                 sc->sc_ekeys_total =
219                     ((mediasize - 1) >> G_ELI_KEY_SHIFT) / blocksize + 1;
220                 sc->sc_ekeys_allocated = 0;
221                 TAILQ_INIT(&sc->sc_ekeys_queue);
222                 RB_INIT(&sc->sc_ekeys_tree);
223                 if (sc->sc_ekeys_total <= g_eli_key_cache_limit) {
224                         uint64_t keyno;
225
226                         for (keyno = 0; keyno < sc->sc_ekeys_total; keyno++)
227                                 (void)g_eli_key_allocate(sc, keyno);
228                         KASSERT(sc->sc_ekeys_total == sc->sc_ekeys_allocated,
229                             ("sc_ekeys_total=%ju != sc_ekeys_allocated=%ju",
230                             (uintmax_t)sc->sc_ekeys_total,
231                             (uintmax_t)sc->sc_ekeys_allocated));
232                 }
233         }
234
235         mtx_unlock(&sc->sc_ekeys_lock);
236 }
237
238 void
239 g_eli_key_destroy(struct g_eli_softc *sc)
240 {
241
242         mtx_lock(&sc->sc_ekeys_lock);
243         if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) {
244                 explicit_bzero(sc->sc_ekey, sizeof(sc->sc_ekey));
245         } else {
246                 struct g_eli_key *key;
247
248                 while ((key = TAILQ_FIRST(&sc->sc_ekeys_queue)) != NULL)
249                         g_eli_key_remove(sc, key);
250                 TAILQ_INIT(&sc->sc_ekeys_queue);
251                 RB_INIT(&sc->sc_ekeys_tree);
252         }
253         mtx_unlock(&sc->sc_ekeys_lock);
254 }
255
256 /*
257  * Select encryption key. If G_ELI_FLAG_SINGLE_KEY is present we only have one
258  * key available for all the data. If the flag is not present select the key
259  * based on data offset.
260  */
261 uint8_t *
262 g_eli_key_hold(struct g_eli_softc *sc, off_t offset, size_t blocksize)
263 {
264         struct g_eli_key *key, keysearch;
265         uint64_t keyno;
266
267         if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0)
268                 return (sc->sc_ekey);
269
270         /* We switch key every 2^G_ELI_KEY_SHIFT blocks. */
271         keyno = (offset >> G_ELI_KEY_SHIFT) / blocksize;
272
273         KASSERT(keyno < sc->sc_ekeys_total,
274             ("%s: keyno=%ju >= sc_ekeys_total=%ju",
275             __func__, (uintmax_t)keyno, (uintmax_t)sc->sc_ekeys_total));
276
277         keysearch.gek_keyno = keyno;
278
279         if (sc->sc_ekeys_total == sc->sc_ekeys_allocated) {
280                 /* We have all the keys, so avoid some overhead. */
281                 key = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch);
282                 KASSERT(key != NULL, ("No key %ju found.", (uintmax_t)keyno));
283                 KASSERT(key->gek_magic == G_ELI_KEY_MAGIC,
284                     ("Invalid key magic."));
285                 return (key->gek_key);
286         }
287
288         mtx_lock(&sc->sc_ekeys_lock);
289         key = RB_FIND(g_eli_key_tree, &sc->sc_ekeys_tree, &keysearch);
290         if (key != NULL) {
291                 g_eli_key_cache_hits++;
292                 TAILQ_REMOVE(&sc->sc_ekeys_queue, key, gek_next);
293                 TAILQ_INSERT_TAIL(&sc->sc_ekeys_queue, key, gek_next);
294         } else {
295                 /*
296                  * No key in cache, find the least recently unreferenced key
297                  * or allocate one if we haven't reached our limit yet.
298                  */
299                 if (sc->sc_ekeys_allocated < g_eli_key_cache_limit) {
300                         key = g_eli_key_allocate(sc, keyno);
301                 } else {
302                         g_eli_key_cache_misses++;
303                         key = g_eli_key_find_last(sc);
304                         if (key != NULL) {
305                                 g_eli_key_replace(sc, key, keyno);
306                         } else {
307                                 /* All keys are referenced? Allocate one. */
308                                 key = g_eli_key_allocate(sc, keyno);
309                         }
310                 }
311         }
312         key->gek_count++;
313         mtx_unlock(&sc->sc_ekeys_lock);
314
315         KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid key magic."));
316
317         return (key->gek_key);
318 }
319
320 void
321 g_eli_key_drop(struct g_eli_softc *sc, uint8_t *rawkey)
322 {
323         struct g_eli_key *key = (struct g_eli_key *)rawkey;
324
325         if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0)
326                 return;
327
328         KASSERT(key->gek_magic == G_ELI_KEY_MAGIC, ("Invalid key magic."));
329
330         if (sc->sc_ekeys_total == sc->sc_ekeys_allocated)
331                 return;
332
333         mtx_lock(&sc->sc_ekeys_lock);
334         KASSERT(key->gek_count > 0, ("key->gek_count=%d", key->gek_count));
335         key->gek_count--;
336         while (sc->sc_ekeys_allocated > g_eli_key_cache_limit) {
337                 key = g_eli_key_find_last(sc);
338                 if (key == NULL)
339                         break;
340                 g_eli_key_remove(sc, key);
341         }
342         mtx_unlock(&sc->sc_ekeys_lock);
343 }
344 #endif /* _KERNEL */