2 * Generic wrapper for storage functions
5 * Copyright (C) 2018-2023 Ondrej Kozina
7 * This file is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This file is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this file; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <sys/types.h>
31 #include "utils_storage_wrappers.h"
34 struct crypt_storage_wrapper {
35 crypt_storage_wrapper_type type;
42 struct crypt_storage *s;
52 static int crypt_storage_backend_init(struct crypt_device *cd,
53 struct crypt_storage_wrapper *w,
57 const char *cipher_mode,
58 const struct volume_key *vk,
62 struct crypt_storage *s;
64 /* iv_start, sector_size */
65 r = crypt_storage_init(&s, sector_size, cipher, cipher_mode, vk->key, vk->keylength, flags & LARGE_IV);
69 if ((flags & DISABLE_KCAPI) && crypt_storage_kernel_only(s)) {
70 log_dbg(cd, "Could not initialize userspace block cipher and kernel fallback is disabled.");
71 crypt_storage_destroy(s);
77 w->u.cb.iv_start = iv_start;
82 static int crypt_storage_dmcrypt_init(
83 struct crypt_device *cd,
84 struct crypt_storage_wrapper *cw,
85 struct device *device,
86 uint64_t device_offset,
89 const char *cipher_spec,
90 struct volume_key *vk,
93 static int counter = 0;
95 struct crypt_dm_active_device dmd = {
96 .flags = CRYPT_ACTIVATE_PRIVATE,
100 log_dbg(cd, "Using temporary dmcrypt to access data.");
102 if (snprintf(cw->u.dm.name, sizeof(cw->u.dm.name), "temporary-cryptsetup-%d-%d", getpid(), counter++) < 0)
104 if (snprintf(path, sizeof(path), "%s/%s", dm_get_dir(), cw->u.dm.name) < 0)
107 r = device_block_adjust(cd, device, DEV_OK,
108 device_offset, &dmd.size, &dmd.flags);
110 log_err(cd, _("Device %s does not exist or access denied."),
111 device_path(device));
115 mode = open_flags | O_DIRECT;
116 if (dmd.flags & CRYPT_ACTIVATE_READONLY)
117 mode = (open_flags & ~O_ACCMODE) | O_RDONLY;
119 if (vk->key_description)
120 dmd.flags |= CRYPT_ACTIVATE_KEYRING_KEY;
122 r = dm_crypt_target_set(&dmd.segment, 0, dmd.size,
134 r = dm_create_device(cd, cw->u.dm.name, "TEMP", &dmd);
136 if (r != -EACCES && r != -ENOTSUP)
137 log_dbg(cd, "error hint would be nice");
141 dm_targets_free(cd, &dmd);
146 fd = open(path, mode);
148 log_dbg(cd, "Failed to open %s", path);
149 dm_remove_device(cd, cw->u.dm.name, CRYPT_DEACTIVATE_FORCE);
154 cw->u.dm.dmcrypt_fd = fd;
159 int crypt_storage_wrapper_init(struct crypt_device *cd,
160 struct crypt_storage_wrapper **cw,
161 struct device *device,
162 uint64_t data_offset,
166 struct volume_key *vk,
170 char _cipher[MAX_CIPHER_LEN], mode[MAX_CIPHER_LEN];
171 struct crypt_storage_wrapper *w;
173 /* device-mapper restrictions */
174 if (data_offset & ((1 << SECTOR_SHIFT) - 1))
177 if (crypt_parse_name_and_mode(cipher, _cipher, NULL, mode))
180 open_flags = O_CLOEXEC | ((flags & OPEN_READONLY) ? O_RDONLY : O_RDWR);
182 w = malloc(sizeof(*w));
186 memset(w, 0, sizeof(*w));
187 w->data_offset = data_offset;
188 w->mem_alignment = device_alignment(device);
189 w->block_size = device_block_size(cd, device);
190 if (!w->block_size || !w->mem_alignment) {
191 log_dbg(cd, "block size or alignment error.");
196 w->dev_fd = device_open(cd, device, open_flags);
202 if (crypt_is_cipher_null(_cipher)) {
203 log_dbg(cd, "Requested cipher_null, switching to noop wrapper.");
210 log_dbg(cd, "no key passed.");
215 r = crypt_storage_backend_init(cd, w, iv_start, sector_size, _cipher, mode, vk, flags);
221 log_dbg(cd, "Failed to initialize userspace block cipher.");
223 if ((r != -ENOTSUP && r != -ENOENT) || (flags & DISABLE_DMCRYPT))
226 r = crypt_storage_dmcrypt_init(cd, w, device, data_offset >> SECTOR_SHIFT, iv_start,
227 sector_size, cipher, vk, open_flags);
229 log_dbg(cd, "Dm-crypt backend failed to initialize.");
235 crypt_storage_wrapper_destroy(w);
236 /* wrapper destroy */
240 /* offset is relative to sector_start */
241 ssize_t crypt_storage_wrapper_read(struct crypt_storage_wrapper *cw,
242 off_t offset, void *buffer, size_t buffer_length)
244 return read_lseek_blockwise(cw->dev_fd,
249 cw->data_offset + offset);
252 ssize_t crypt_storage_wrapper_read_decrypt(struct crypt_storage_wrapper *cw,
253 off_t offset, void *buffer, size_t buffer_length)
258 if (cw->type == DMCRYPT)
259 return read_lseek_blockwise(cw->u.dm.dmcrypt_fd,
266 read = read_lseek_blockwise(cw->dev_fd,
271 cw->data_offset + offset);
272 if (cw->type == NONE || read < 0)
275 r = crypt_storage_decrypt(cw->u.cb.s,
276 cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
285 ssize_t crypt_storage_wrapper_decrypt(struct crypt_storage_wrapper *cw,
286 off_t offset, void *buffer, size_t buffer_length)
291 if (cw->type == NONE)
294 if (cw->type == DMCRYPT) {
295 /* there's nothing we can do, just read/decrypt via dm-crypt */
296 read = crypt_storage_wrapper_read_decrypt(cw, offset, buffer, buffer_length);
297 if (read < 0 || (size_t)read != buffer_length)
302 r = crypt_storage_decrypt(cw->u.cb.s,
303 cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
312 ssize_t crypt_storage_wrapper_write(struct crypt_storage_wrapper *cw,
313 off_t offset, void *buffer, size_t buffer_length)
315 return write_lseek_blockwise(cw->dev_fd,
320 cw->data_offset + offset);
323 ssize_t crypt_storage_wrapper_encrypt_write(struct crypt_storage_wrapper *cw,
324 off_t offset, void *buffer, size_t buffer_length)
326 if (cw->type == DMCRYPT)
327 return write_lseek_blockwise(cw->u.dm.dmcrypt_fd,
334 if (cw->type == USPACE &&
335 crypt_storage_encrypt(cw->u.cb.s,
336 cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
337 buffer_length, buffer))
340 return write_lseek_blockwise(cw->dev_fd,
345 cw->data_offset + offset);
348 ssize_t crypt_storage_wrapper_encrypt(struct crypt_storage_wrapper *cw,
349 off_t offset, void *buffer, size_t buffer_length)
351 if (cw->type == NONE)
354 if (cw->type == DMCRYPT)
357 if (crypt_storage_encrypt(cw->u.cb.s,
358 cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
366 void crypt_storage_wrapper_destroy(struct crypt_storage_wrapper *cw)
371 if (cw->type == USPACE)
372 crypt_storage_destroy(cw->u.cb.s);
373 if (cw->type == DMCRYPT) {
374 close(cw->u.dm.dmcrypt_fd);
375 dm_remove_device(NULL, cw->u.dm.name, CRYPT_DEACTIVATE_FORCE);
381 int crypt_storage_wrapper_datasync(const struct crypt_storage_wrapper *cw)
385 if (cw->type == DMCRYPT)
386 return fdatasync(cw->u.dm.dmcrypt_fd);
388 return fdatasync(cw->dev_fd);
391 crypt_storage_wrapper_type crypt_storage_wrapper_get_type(const struct crypt_storage_wrapper *cw)
393 return cw ? cw->type : NONE;