"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/lib/luks2/luks2_segment.c" (13 Jan 2022, 10886 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 "luks2_segment.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.2_vs_2.4.3.

    1 /*
    2  * LUKS - Linux Unified Key Setup v2, internal segment handling
    3  *
    4  * Copyright (C) 2018-2021, Red Hat, Inc. All rights reserved.
    5  * Copyright (C) 2018-2021, Ondrej Kozina
    6  *
    7  * This program is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU General Public License
    9  * as published by the Free Software Foundation; either version 2
   10  * of the License, or (at your option) any later version.
   11  *
   12  * This program 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
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   20  */
   21 
   22 #include "luks2_internal.h"
   23 
   24 /* use only on already validated 'segments' object */
   25 uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise)
   26 {
   27     uint64_t tmp, min = blockwise ? UINT64_MAX >> SECTOR_SHIFT : UINT64_MAX;
   28 
   29     if (!jobj_segments)
   30         return 0;
   31 
   32     json_object_object_foreach(jobj_segments, key, val) {
   33         UNUSED(key);
   34 
   35         if (json_segment_is_backup(val))
   36             continue;
   37 
   38         tmp = json_segment_get_offset(val, blockwise);
   39 
   40         if (!tmp)
   41             return tmp;
   42 
   43         if (tmp < min)
   44             min = tmp;
   45     }
   46 
   47     return min;
   48 }
   49 
   50 uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise)
   51 {
   52     json_object *jobj;
   53 
   54     if (!jobj_segment ||
   55         !json_object_object_get_ex(jobj_segment, "offset", &jobj))
   56         return 0;
   57 
   58     return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);
   59 }
   60 
   61 const char *json_segment_type(json_object *jobj_segment)
   62 {
   63     json_object *jobj;
   64 
   65     if (!jobj_segment ||
   66         !json_object_object_get_ex(jobj_segment, "type", &jobj))
   67         return NULL;
   68 
   69     return json_object_get_string(jobj);
   70 }
   71 
   72 uint64_t json_segment_get_iv_offset(json_object *jobj_segment)
   73 {
   74     json_object *jobj;
   75 
   76     if (!jobj_segment ||
   77         !json_object_object_get_ex(jobj_segment, "iv_tweak", &jobj))
   78         return 0;
   79 
   80     return crypt_jobj_get_uint64(jobj);
   81 }
   82 
   83 uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise)
   84 {
   85     json_object *jobj;
   86 
   87     if (!jobj_segment ||
   88         !json_object_object_get_ex(jobj_segment, "size", &jobj))
   89         return 0;
   90 
   91     return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);
   92 }
   93 
   94 const char *json_segment_get_cipher(json_object *jobj_segment)
   95 {
   96     json_object *jobj;
   97 
   98     /* FIXME: Pseudo "null" cipher should be handled elsewhere */
   99     if (!jobj_segment ||
  100         !json_object_object_get_ex(jobj_segment, "encryption", &jobj))
  101         return "null";
  102 
  103     return json_object_get_string(jobj);
  104 }
  105 
  106 int json_segment_get_sector_size(json_object *jobj_segment)
  107 {
  108     json_object *jobj;
  109 
  110     if (!jobj_segment ||
  111             !json_object_object_get_ex(jobj_segment, "sector_size", &jobj))
  112         return -1;
  113 
  114     return json_object_get_int(jobj);
  115 }
  116 
  117 static json_object *json_segment_get_flags(json_object *jobj_segment)
  118 {
  119     json_object *jobj;
  120 
  121     if (!jobj_segment || !(json_object_object_get_ex(jobj_segment, "flags", &jobj)))
  122         return NULL;
  123     return jobj;
  124 }
  125 
  126 bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
  127 {
  128     int r, i;
  129     json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
  130 
  131     if (!jobj_flags)
  132         return false;
  133 
  134     for (i = 0; i < (int)json_object_array_length(jobj_flags); i++) {
  135         jobj = json_object_array_get_idx(jobj_flags, i);
  136         if (len)
  137             r = strncmp(json_object_get_string(jobj), flag_str, len);
  138         else
  139             r = strcmp(json_object_get_string(jobj), flag_str);
  140         if (!r)
  141             return true;
  142     }
  143 
  144     return false;
  145 }
  146 
  147 bool json_segment_is_backup(json_object *jobj_segment)
  148 {
  149     return json_segment_contains_flag(jobj_segment, "backup-", 7);
  150 }
  151 
  152 json_object *json_segments_get_segment(json_object *jobj_segments, int segment)
  153 {
  154     json_object *jobj;
  155     char segment_name[16];
  156 
  157     if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
  158         return NULL;
  159 
  160     if (!json_object_object_get_ex(jobj_segments, segment_name, &jobj))
  161         return NULL;
  162 
  163     return jobj;
  164 }
  165 
  166 unsigned json_segments_count(json_object *jobj_segments)
  167 {
  168     unsigned count = 0;
  169 
  170     if (!jobj_segments)
  171         return 0;
  172 
  173     json_object_object_foreach(jobj_segments, slot, val) {
  174         UNUSED(slot);
  175         if (!json_segment_is_backup(val))
  176             count++;
  177     }
  178 
  179     return count;
  180 }
  181 
  182 static void _get_segment_or_id_by_flag(json_object *jobj_segments, const char *flag, unsigned id, void *retval)
  183 {
  184     json_object *jobj_flags, **jobj_ret = (json_object **)retval;
  185     int *ret = (int *)retval;
  186 
  187     if (!flag)
  188         return;
  189 
  190     json_object_object_foreach(jobj_segments, key, value) {
  191         if (!json_object_object_get_ex(value, "flags", &jobj_flags))
  192             continue;
  193         if (LUKS2_array_jobj(jobj_flags, flag)) {
  194             if (id)
  195                 *ret = atoi(key);
  196             else
  197                 *jobj_ret = value;
  198             return;
  199         }
  200     }
  201 }
  202 
  203 void json_segment_remove_flag(json_object *jobj_segment, const char *flag)
  204 {
  205     json_object *jobj_flags, *jobj_flags_new;
  206 
  207     if (!jobj_segment)
  208         return;
  209 
  210     jobj_flags = json_segment_get_flags(jobj_segment);
  211     if (!jobj_flags)
  212         return;
  213 
  214     jobj_flags_new = LUKS2_array_remove(jobj_flags, flag);
  215     if (!jobj_flags_new)
  216         return;
  217 
  218     if (json_object_array_length(jobj_flags_new) <= 0) {
  219         json_object_put(jobj_flags_new);
  220         json_object_object_del(jobj_segment, "flags");
  221     } else
  222         json_object_object_add(jobj_segment, "flags", jobj_flags_new);
  223 }
  224 
  225 static json_object *_segment_create_generic(const char *type, uint64_t offset, const uint64_t *length)
  226 {
  227     json_object *jobj = json_object_new_object();
  228     if (!jobj)
  229         return NULL;
  230 
  231     json_object_object_add(jobj, "type",        json_object_new_string(type));
  232     json_object_object_add(jobj, "offset",      crypt_jobj_new_uint64(offset));
  233     json_object_object_add(jobj, "size",        length ? crypt_jobj_new_uint64(*length) : json_object_new_string("dynamic"));
  234 
  235     return jobj;
  236 }
  237 
  238 json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption)
  239 {
  240     json_object *jobj = _segment_create_generic("linear", offset, length);
  241     if (reencryption)
  242         LUKS2_segment_set_flag(jobj, "in-reencryption");
  243     return jobj;
  244 }
  245 
  246 json_object *json_segment_create_crypt(uint64_t offset,
  247                   uint64_t iv_offset, const uint64_t *length,
  248                   const char *cipher, uint32_t sector_size,
  249                   unsigned reencryption)
  250 {
  251     json_object *jobj = _segment_create_generic("crypt", offset, length);
  252     if (!jobj)
  253         return NULL;
  254 
  255     json_object_object_add(jobj, "iv_tweak",    crypt_jobj_new_uint64(iv_offset));
  256     json_object_object_add(jobj, "encryption",  json_object_new_string(cipher));
  257     json_object_object_add(jobj, "sector_size", json_object_new_int(sector_size));
  258     if (reencryption)
  259         LUKS2_segment_set_flag(jobj, "in-reencryption");
  260 
  261     return jobj;
  262 }
  263 
  264 uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr, int segment, unsigned blockwise)
  265 {
  266     return json_segment_get_offset(LUKS2_get_segment_jobj(hdr, segment), blockwise);
  267 }
  268 
  269 int json_segments_segment_in_reencrypt(json_object *jobj_segments)
  270 {
  271     json_object *jobj_flags;
  272 
  273     json_object_object_foreach(jobj_segments, slot, val) {
  274         if (!json_object_object_get_ex(val, "flags", &jobj_flags) ||
  275             !LUKS2_array_jobj(jobj_flags, "in-reencryption"))
  276             continue;
  277 
  278         return atoi(slot);
  279     }
  280 
  281     return -1;
  282 }
  283 
  284 uint64_t LUKS2_segment_size(struct luks2_hdr *hdr, int segment, unsigned blockwise)
  285 {
  286     return json_segment_get_size(LUKS2_get_segment_jobj(hdr, segment), blockwise);
  287 }
  288 
  289 int LUKS2_segment_is_type(struct luks2_hdr *hdr, int segment, const char *type)
  290 {
  291     return !strcmp(json_segment_type(LUKS2_get_segment_jobj(hdr, segment)) ?: "", type);
  292 }
  293 
  294 int LUKS2_last_segment_by_type(struct luks2_hdr *hdr, const char *type)
  295 {
  296     json_object *jobj_segments;
  297     int last_found = -1;
  298 
  299     if (!type)
  300         return -1;
  301 
  302     if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
  303         return -1;
  304 
  305     json_object_object_foreach(jobj_segments, slot, val) {
  306         if (json_segment_is_backup(val))
  307             continue;
  308         if (strcmp(type, json_segment_type(val) ?: ""))
  309             continue;
  310 
  311         if (atoi(slot) > last_found)
  312             last_found = atoi(slot);
  313     }
  314 
  315     return last_found;
  316 }
  317 
  318 int LUKS2_segment_by_type(struct luks2_hdr *hdr, const char *type)
  319 {
  320     json_object *jobj_segments;
  321     int first_found = -1;
  322 
  323     if (!type)
  324         return -EINVAL;
  325 
  326     if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
  327         return -EINVAL;
  328 
  329     json_object_object_foreach(jobj_segments, slot, val) {
  330         if (json_segment_is_backup(val))
  331             continue;
  332         if (strcmp(type, json_segment_type(val) ?: ""))
  333             continue;
  334 
  335         if (first_found < 0)
  336             first_found = atoi(slot);
  337         else if (atoi(slot) < first_found)
  338             first_found = atoi(slot);
  339     }
  340 
  341     return first_found;
  342 }
  343 
  344 int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr)
  345 {
  346     json_object *jobj_segments;
  347     int id, last_id = -1;
  348 
  349     if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
  350         return -EINVAL;
  351 
  352     json_object_object_foreach(jobj_segments, slot, val) {
  353         UNUSED(val);
  354         id = atoi(slot);
  355         if (id > last_id)
  356             last_id = id;
  357     }
  358 
  359     return last_id + 1;
  360 }
  361 
  362 int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag)
  363 {
  364     json_object *jobj_flags;
  365 
  366     if (!jobj_segment || !flag)
  367         return -EINVAL;
  368 
  369     if (!json_object_object_get_ex(jobj_segment, "flags", &jobj_flags)) {
  370         jobj_flags = json_object_new_array();
  371         if (!jobj_flags)
  372             return -ENOMEM;
  373         json_object_object_add(jobj_segment, "flags", jobj_flags);
  374     }
  375 
  376     if (LUKS2_array_jobj(jobj_flags, flag))
  377         return 0;
  378 
  379     json_object_array_add(jobj_flags, json_object_new_string(flag));
  380 
  381     return 0;
  382 }
  383 
  384 int LUKS2_segments_set(struct crypt_device *cd, struct luks2_hdr *hdr,
  385                json_object *jobj_segments, int commit)
  386 {
  387     json_object_object_add(hdr->jobj, "segments", jobj_segments);
  388 
  389     return commit ? LUKS2_hdr_write(cd, hdr) : 0;
  390 }
  391 
  392 int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag)
  393 {
  394     int ret = -ENOENT;
  395     json_object *jobj_segments = LUKS2_get_segments_jobj(hdr);
  396 
  397     if (jobj_segments)
  398         _get_segment_or_id_by_flag(jobj_segments, flag, 1, &ret);
  399 
  400     return ret;
  401 }
  402 
  403 json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
  404 {
  405     json_object *jobj_segment = NULL,
  406             *jobj_segments = LUKS2_get_segments_jobj(hdr);
  407 
  408     if (jobj_segments)
  409         _get_segment_or_id_by_flag(jobj_segments, flag, 0, &jobj_segment);
  410 
  411     return jobj_segment;
  412 }
  413 
  414 /* compares key characteristics of both segments */
  415 bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2)
  416 {
  417     const char *type = json_segment_type(jobj_segment_1);
  418     const char *type2 = json_segment_type(jobj_segment_2);
  419 
  420     if (!type || !type2)
  421         return false;
  422 
  423     if (strcmp(type, type2))
  424         return false;
  425 
  426     if (!strcmp(type, "crypt"))
  427         return (json_segment_get_sector_size(jobj_segment_1) == json_segment_get_sector_size(jobj_segment_2) &&
  428             !strcmp(json_segment_get_cipher(jobj_segment_1),
  429                     json_segment_get_cipher(jobj_segment_2)));
  430 
  431     return true;
  432 }