"Fossies" - the Fresh Open Source Software Archive 
Member "cryptsetup-2.4.3/lib/utils_storage_wrappers.c" (13 Jan 2022, 9094 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "utils_storage_wrappers.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * Generic wrapper for storage functions
3 * (experimental only)
4 *
5 * Copyright (C) 2018-2021, Ondrej Kozina
6 *
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.
11 *
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.
16 *
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.
20 */
21
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stddef.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <limits.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30
31 #include "utils_storage_wrappers.h"
32 #include "internal.h"
33
34 struct crypt_storage_wrapper {
35 crypt_storage_wrapper_type type;
36 int dev_fd;
37 int block_size;
38 size_t mem_alignment;
39 uint64_t data_offset;
40 union {
41 struct {
42 struct crypt_storage *s;
43 uint64_t iv_start;
44 } cb;
45 struct {
46 int dmcrypt_fd;
47 char name[PATH_MAX];
48 } dm;
49 } u;
50 };
51
52 static int crypt_storage_backend_init(struct crypt_device *cd,
53 struct crypt_storage_wrapper *w,
54 uint64_t iv_start,
55 int sector_size,
56 const char *cipher,
57 const char *cipher_mode,
58 const struct volume_key *vk,
59 uint32_t flags)
60 {
61 int r;
62 struct crypt_storage *s;
63
64 /* iv_start, sector_size */
65 r = crypt_storage_init(&s, sector_size, cipher, cipher_mode, vk->key, vk->keylength, flags & LARGE_IV);
66 if (r)
67 return r;
68
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);
72 return -ENOTSUP;
73 }
74
75 w->type = USPACE;
76 w->u.cb.s = s;
77 w->u.cb.iv_start = iv_start;
78
79 return 0;
80 }
81
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,
87 uint64_t iv_start,
88 int sector_size,
89 const char *cipher_spec,
90 struct volume_key *vk,
91 int open_flags)
92 {
93 static int counter = 0;
94 char path[PATH_MAX];
95 struct crypt_dm_active_device dmd = {
96 .flags = CRYPT_ACTIVATE_PRIVATE,
97 };
98 int mode, r, fd = -1;
99
100 log_dbg(cd, "Using temporary dmcrypt to access data.");
101
102 if (snprintf(cw->u.dm.name, sizeof(cw->u.dm.name), "temporary-cryptsetup-%d-%d", getpid(), counter++) < 0)
103 return -ENOMEM;
104 if (snprintf(path, sizeof(path), "%s/%s", dm_get_dir(), cw->u.dm.name) < 0)
105 return -ENOMEM;
106
107 r = device_block_adjust(cd, device, DEV_OK,
108 device_offset, &dmd.size, &dmd.flags);
109 if (r < 0) {
110 log_err(cd, _("Device %s does not exist or access denied."),
111 device_path(device));
112 return -EIO;
113 }
114
115 mode = open_flags | O_DIRECT;
116 if (dmd.flags & CRYPT_ACTIVATE_READONLY)
117 mode = (open_flags & ~O_ACCMODE) | O_RDONLY;
118
119 if (vk->key_description)
120 dmd.flags |= CRYPT_ACTIVATE_KEYRING_KEY;
121
122 r = dm_crypt_target_set(&dmd.segment, 0, dmd.size,
123 device,
124 vk,
125 cipher_spec,
126 iv_start,
127 device_offset,
128 NULL,
129 0,
130 sector_size);
131 if (r)
132 return r;
133
134 r = dm_create_device(cd, cw->u.dm.name, "TEMP", &dmd);
135 if (r < 0) {
136 if (r != -EACCES && r != -ENOTSUP)
137 log_dbg(cd, "error hint would be nice");
138 r = -EIO;
139 }
140
141 dm_targets_free(cd, &dmd);
142
143 if (r)
144 return r;
145
146 fd = open(path, mode);
147 if (fd < 0) {
148 log_dbg(cd, "Failed to open %s", path);
149 dm_remove_device(cd, cw->u.dm.name, CRYPT_DEACTIVATE_FORCE);
150 return -EINVAL;
151 }
152
153 cw->type = DMCRYPT;
154 cw->u.dm.dmcrypt_fd = fd;
155
156 return 0;
157 }
158
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,
163 uint64_t iv_start,
164 int sector_size,
165 const char *cipher,
166 struct volume_key *vk,
167 uint32_t flags)
168 {
169 int open_flags, r;
170 char _cipher[MAX_CIPHER_LEN], mode[MAX_CIPHER_LEN];
171 struct crypt_storage_wrapper *w;
172
173 /* device-mapper restrictions */
174 if (data_offset & ((1 << SECTOR_SHIFT) - 1))
175 return -EINVAL;
176
177 if (crypt_parse_name_and_mode(cipher, _cipher, NULL, mode))
178 return -EINVAL;
179
180 open_flags = O_CLOEXEC | ((flags & OPEN_READONLY) ? O_RDONLY : O_RDWR);
181
182 w = malloc(sizeof(*w));
183 if (!w)
184 return -ENOMEM;
185
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.");
192 r = -EINVAL;
193 goto err;
194 }
195
196 w->dev_fd = device_open(cd, device, open_flags);
197 if (w->dev_fd < 0) {
198 r = -EINVAL;
199 goto err;
200 }
201
202 if (crypt_is_cipher_null(_cipher)) {
203 log_dbg(cd, "Requested cipher_null, switching to noop wrapper.");
204 w->type = NONE;
205 *cw = w;
206 return 0;
207 }
208
209 if (!vk) {
210 log_dbg(cd, "no key passed.");
211 r = -EINVAL;
212 goto err;
213 }
214
215 r = crypt_storage_backend_init(cd, w, iv_start, sector_size, _cipher, mode, vk, flags);
216 if (!r) {
217 *cw = w;
218 return 0;
219 }
220
221 log_dbg(cd, "Failed to initialize userspace block cipher.");
222
223 if ((r != -ENOTSUP && r != -ENOENT) || (flags & DISABLE_DMCRYPT))
224 goto err;
225
226 r = crypt_storage_dmcrypt_init(cd, w, device, data_offset >> SECTOR_SHIFT, iv_start,
227 sector_size, cipher, vk, open_flags);
228 if (r) {
229 log_dbg(cd, "Dm-crypt backend failed to initialize.");
230 goto err;
231 }
232 *cw = w;
233 return 0;
234 err:
235 crypt_storage_wrapper_destroy(w);
236 /* wrapper destroy */
237 return r;
238 }
239
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)
243 {
244 return read_lseek_blockwise(cw->dev_fd,
245 cw->block_size,
246 cw->mem_alignment,
247 buffer,
248 buffer_length,
249 cw->data_offset + offset);
250 }
251
252 ssize_t crypt_storage_wrapper_read_decrypt(struct crypt_storage_wrapper *cw,
253 off_t offset, void *buffer, size_t buffer_length)
254 {
255 int r;
256 ssize_t read;
257
258 if (cw->type == DMCRYPT)
259 return read_lseek_blockwise(cw->u.dm.dmcrypt_fd,
260 cw->block_size,
261 cw->mem_alignment,
262 buffer,
263 buffer_length,
264 offset);
265
266 read = read_lseek_blockwise(cw->dev_fd,
267 cw->block_size,
268 cw->mem_alignment,
269 buffer,
270 buffer_length,
271 cw->data_offset + offset);
272 if (cw->type == NONE || read < 0)
273 return read;
274
275 r = crypt_storage_decrypt(cw->u.cb.s,
276 cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
277 read,
278 buffer);
279 if (r)
280 return -EINVAL;
281
282 return read;
283 }
284
285 ssize_t crypt_storage_wrapper_decrypt(struct crypt_storage_wrapper *cw,
286 off_t offset, void *buffer, size_t buffer_length)
287 {
288 int r;
289 ssize_t read;
290
291 if (cw->type == NONE)
292 return 0;
293
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)
298 return -EINVAL;
299 return 0;
300 }
301
302 r = crypt_storage_decrypt(cw->u.cb.s,
303 cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
304 buffer_length,
305 buffer);
306 if (r)
307 return r;
308
309 return 0;
310 }
311
312 ssize_t crypt_storage_wrapper_write(struct crypt_storage_wrapper *cw,
313 off_t offset, void *buffer, size_t buffer_length)
314 {
315 return write_lseek_blockwise(cw->dev_fd,
316 cw->block_size,
317 cw->mem_alignment,
318 buffer,
319 buffer_length,
320 cw->data_offset + offset);
321 }
322
323 ssize_t crypt_storage_wrapper_encrypt_write(struct crypt_storage_wrapper *cw,
324 off_t offset, void *buffer, size_t buffer_length)
325 {
326 if (cw->type == DMCRYPT)
327 return write_lseek_blockwise(cw->u.dm.dmcrypt_fd,
328 cw->block_size,
329 cw->mem_alignment,
330 buffer,
331 buffer_length,
332 offset);
333
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))
338 return -EINVAL;
339
340 return write_lseek_blockwise(cw->dev_fd,
341 cw->block_size,
342 cw->mem_alignment,
343 buffer,
344 buffer_length,
345 cw->data_offset + offset);
346 }
347
348 ssize_t crypt_storage_wrapper_encrypt(struct crypt_storage_wrapper *cw,
349 off_t offset, void *buffer, size_t buffer_length)
350 {
351 if (cw->type == NONE)
352 return 0;
353
354 if (cw->type == DMCRYPT)
355 return -ENOTSUP;
356
357 if (crypt_storage_encrypt(cw->u.cb.s,
358 cw->u.cb.iv_start + (offset >> SECTOR_SHIFT),
359 buffer_length,
360 buffer))
361 return -EINVAL;
362
363 return 0;
364 }
365
366 void crypt_storage_wrapper_destroy(struct crypt_storage_wrapper *cw)
367 {
368 if (!cw)
369 return;
370
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);
376 }
377
378 free(cw);
379 }
380
381 int crypt_storage_wrapper_datasync(const struct crypt_storage_wrapper *cw)
382 {
383 if (!cw)
384 return -EINVAL;
385 if (cw->type == DMCRYPT)
386 return fdatasync(cw->u.dm.dmcrypt_fd);
387 else
388 return fdatasync(cw->dev_fd);
389 }
390
391 crypt_storage_wrapper_type crypt_storage_wrapper_get_type(const struct crypt_storage_wrapper *cw)
392 {
393 return cw ? cw->type : NONE;
394 }