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