8708ba527792d9724f4d0c8c6c5a32e2f9e0a062
[platform/upstream/cryptsetup.git] / lib / luks2 / luks2_segment.c
1 /*
2  * LUKS - Linux Unified Key Setup v2, internal segment handling
3  *
4  * Copyright (C) 2018-2020, Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2018-2020, 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 static 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 }