Imported Upstream version 2.6.1
[platform/upstream/cryptsetup.git] / lib / utils_storage_wrappers.c
1 /*
2  * Generic wrapper for storage functions
3  * (experimental only)
4  *
5  * Copyright (C) 2018-2023 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 }