4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 #include <gnutls/crypto.h>
46 #include <nbdkit-filter.h>
48 #include "luks-encryption.h"
51 #include "isaligned.h"
54 static char *passphrase
= NULL
;
59 /* XXX We should really store the passphrase (and master key)
63 memset (passphrase
, 0, strlen (passphrase
));
69 luks_thread_model (void)
71 return NBDKIT_THREAD_MODEL_PARALLEL
;
75 luks_config (nbdkit_next_config
*next
, nbdkit_backend
*nxdata
,
76 const char *key
, const char *value
)
78 if (strcmp (key
, "passphrase") == 0) {
79 if (nbdkit_read_password (value
, &passphrase
) == -1)
84 return next (nxdata
, key
, value
);
88 luks_config_complete (nbdkit_next_config_complete
*next
, nbdkit_backend
*nxdata
)
90 if (passphrase
== NULL
) {
91 nbdkit_error ("LUKS \"passphrase\" parameter is missing");
97 #define luks_config_help \
98 "passphrase=<SECRET> Secret passphrase."
100 /* Per-connection handle. */
106 luks_open (nbdkit_next_open
*next
, nbdkit_context
*nxdata
,
107 int readonly
, const char *exportname
, int is_tls
)
111 if (next (nxdata
, readonly
, exportname
) == -1)
114 h
= calloc (1, sizeof *h
);
116 nbdkit_error ("calloc: %m");
124 luks_close (void *handle
)
126 struct handle
*h
= handle
;
128 free_luks_data (h
->h
);
133 luks_prepare (nbdkit_next
*next
, void *handle
, int readonly
)
135 struct handle
*h
= handle
;
137 /* Check we haven't been called before, this should never happen. */
138 assert (h
->h
== NULL
);
140 h
->h
= load_header (next
, passphrase
);
148 luks_get_size (nbdkit_next
*next
, void *handle
)
150 struct handle
*h
= handle
;
153 /* Check that prepare has been called already. */
154 assert (h
->h
!= NULL
);
156 const uint64_t payload_offset
= get_payload_offset (h
->h
) * LUKS_SECTOR_SIZE
;
158 size
= next
->get_size (next
);
162 if (size
< payload_offset
) {
163 nbdkit_error ("disk too small, or contains an incomplete LUKS partition");
167 return size
- payload_offset
;
170 /* Whatever the plugin says, several operations are not supported by
178 luks_can_extents (nbdkit_next
*next
, void *handle
)
184 luks_can_trim (nbdkit_next
*next
, void *handle
)
190 luks_can_zero (nbdkit_next
*next
, void *handle
)
192 return NBDKIT_ZERO_EMULATE
;
196 luks_can_fast_zero (nbdkit_next
*next
, void *handle
)
201 /* Rely on nbdkit to call .pread to emulate .cache calls. We will
202 * respond by decrypting the block which could be stored by the cache
203 * filter or similar on top.
206 luks_can_cache (nbdkit_next
*next
, void *handle
)
208 return NBDKIT_CACHE_EMULATE
;
211 /* Advertise minimum/preferred sector-sized blocks, although we can in
212 * fact handle any read or write.
215 luks_block_size (nbdkit_next
*next
, void *handle
,
216 uint32_t *minimum
, uint32_t *preferred
, uint32_t *maximum
)
218 if (next
->block_size (next
, minimum
, preferred
, maximum
) == -1)
221 if (*minimum
== 0) { /* No constraints set by the plugin. */
222 *minimum
= LUKS_SECTOR_SIZE
;
223 *preferred
= LUKS_SECTOR_SIZE
;
224 *maximum
= 0xffffffff;
227 *minimum
= MAX (*minimum
, LUKS_SECTOR_SIZE
);
228 *preferred
= MAX (*minimum
, MAX (*preferred
, LUKS_SECTOR_SIZE
));
235 luks_pread (nbdkit_next
*next
, void *handle
,
236 void *buf
, uint32_t count
, uint64_t offset
,
237 uint32_t flags
, int *err
)
239 struct handle
*h
= handle
;
240 const uint64_t payload_offset
= get_payload_offset (h
->h
) * LUKS_SECTOR_SIZE
;
241 CLEANUP_FREE
uint8_t *sector
= NULL
;
242 uint64_t sectnum
, sectoffs
;
243 gnutls_cipher_hd_t cipher
;
250 if (!IS_ALIGNED (count
| offset
, LUKS_SECTOR_SIZE
)) {
251 sector
= malloc (LUKS_SECTOR_SIZE
);
252 if (sector
== NULL
) {
254 nbdkit_error ("malloc: %m");
259 sectnum
= offset
/ LUKS_SECTOR_SIZE
; /* sector number */
260 sectoffs
= offset
% LUKS_SECTOR_SIZE
; /* offset within the sector */
262 cipher
= create_cipher (h
->h
);
268 uint64_t n
= MIN (LUKS_SECTOR_SIZE
- sectoffs
, count
);
271 if (next
->pread (next
, sector
, LUKS_SECTOR_SIZE
,
272 sectnum
* LUKS_SECTOR_SIZE
+ payload_offset
,
276 if (do_decrypt (h
->h
, cipher
, sectnum
, sector
, 1) == -1)
279 memcpy (buf
, §or
[sectoffs
], n
);
287 while (count
>= LUKS_SECTOR_SIZE
) {
288 if (next
->pread (next
, buf
, LUKS_SECTOR_SIZE
,
289 sectnum
* LUKS_SECTOR_SIZE
+ payload_offset
,
293 if (do_decrypt (h
->h
, cipher
, sectnum
, buf
, 1) == -1)
296 buf
+= LUKS_SECTOR_SIZE
;
297 count
-= LUKS_SECTOR_SIZE
;
304 if (next
->pread (next
, sector
, LUKS_SECTOR_SIZE
,
305 sectnum
* LUKS_SECTOR_SIZE
+ payload_offset
,
309 if (do_decrypt (h
->h
, cipher
, sectnum
, sector
, 1) == -1)
312 memcpy (buf
, sector
, count
);
315 gnutls_cipher_deinit (cipher
);
319 gnutls_cipher_deinit (cipher
);
323 /* Lock preventing read-modify-write cycles from overlapping. */
324 static pthread_mutex_t read_modify_write_lock
= PTHREAD_MUTEX_INITIALIZER
;
328 luks_pwrite (nbdkit_next
*next
, void *handle
,
329 const void *buf
, uint32_t count
, uint64_t offset
,
330 uint32_t flags
, int *err
)
332 struct handle
*h
= handle
;
333 const uint64_t payload_offset
= get_payload_offset (h
->h
) * LUKS_SECTOR_SIZE
;
334 CLEANUP_FREE
uint8_t *sector
= NULL
;
335 uint64_t sectnum
, sectoffs
;
336 gnutls_cipher_hd_t cipher
;
343 sector
= malloc (LUKS_SECTOR_SIZE
);
344 if (sector
== NULL
) {
346 nbdkit_error ("malloc: %m");
350 sectnum
= offset
/ LUKS_SECTOR_SIZE
; /* sector number */
351 sectoffs
= offset
% LUKS_SECTOR_SIZE
; /* offset within the sector */
353 cipher
= create_cipher (h
->h
);
359 ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&read_modify_write_lock
);
361 uint64_t n
= MIN (LUKS_SECTOR_SIZE
- sectoffs
, count
);
363 if (next
->pread (next
, sector
, LUKS_SECTOR_SIZE
,
364 sectnum
* LUKS_SECTOR_SIZE
+ payload_offset
,
368 memcpy (§or
[sectoffs
], buf
, n
);
370 if (do_encrypt (h
->h
, cipher
, sectnum
, sector
, 1) == -1)
373 if (next
->pwrite (next
, sector
, LUKS_SECTOR_SIZE
,
374 sectnum
* LUKS_SECTOR_SIZE
+ payload_offset
,
384 while (count
>= LUKS_SECTOR_SIZE
) {
385 memcpy (sector
, buf
, LUKS_SECTOR_SIZE
);
387 if (do_encrypt (h
->h
, cipher
, sectnum
, sector
, 1) == -1)
390 if (next
->pwrite (next
, sector
, LUKS_SECTOR_SIZE
,
391 sectnum
* LUKS_SECTOR_SIZE
+ payload_offset
,
395 buf
+= LUKS_SECTOR_SIZE
;
396 count
-= LUKS_SECTOR_SIZE
;
402 ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&read_modify_write_lock
);
404 if (next
->pread (next
, sector
, LUKS_SECTOR_SIZE
,
405 sectnum
* LUKS_SECTOR_SIZE
+ payload_offset
,
409 memcpy (sector
, buf
, count
);
411 if (do_encrypt (h
->h
, cipher
, sectnum
, sector
, 1) == -1)
414 if (next
->pwrite (next
, sector
, LUKS_SECTOR_SIZE
,
415 sectnum
* LUKS_SECTOR_SIZE
+ payload_offset
,
420 gnutls_cipher_deinit (cipher
);
424 gnutls_cipher_deinit (cipher
);
428 static struct nbdkit_filter filter
= {
430 .longname
= "nbdkit luks filter",
431 .unload
= luks_unload
,
432 .thread_model
= luks_thread_model
,
433 .config
= luks_config
,
434 .config_complete
= luks_config_complete
,
435 .config_help
= luks_config_help
,
438 .prepare
= luks_prepare
,
439 .get_size
= luks_get_size
,
440 .can_extents
= luks_can_extents
,
441 .can_trim
= luks_can_trim
,
442 .can_zero
= luks_can_zero
,
443 .can_fast_zero
= luks_can_fast_zero
,
444 .can_cache
= luks_can_cache
,
445 .block_size
= luks_block_size
,
447 .pwrite
= luks_pwrite
,
450 NBDKIT_REGISTER_FILTER (filter
)