"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 }