Coverage Report

Created: 2025-06-13 07:22

/src/libfvde/libfvde/libfvde_metadata_block.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Metadata block functions
3
 *
4
 * Copyright (C) 2011-2024, Omar Choudary <choudary.omar@gmail.com>
5
 *                          Joachim Metz <joachim.metz@gmail.com>
6
 *
7
 * Refer to AUTHORS for acknowledgements.
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation, either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
21
 */
22
23
#include <common.h>
24
#include <byte_stream.h>
25
#include <memory.h>
26
#include <types.h>
27
28
#include "libfvde_checksum.h"
29
#include "libfvde_libcerror.h"
30
#include "libfvde_libcnotify.h"
31
#include "libfvde_metadata_block.h"
32
#include "libfvde_types.h"
33
34
#include "fvde_metadata.h"
35
36
/* Creates a metadata block
37
 * Make sure the value metadata_block is referencing, is set to NULL
38
 * Returns 1 if successful or -1 on error
39
 */
40
int libfvde_metadata_block_initialize(
41
     libfvde_metadata_block_t **metadata_block,
42
     libcerror_error_t **error )
43
875
{
44
875
  static char *function = "libfvde_metadata_block_initialize";
45
46
875
  if( metadata_block == NULL )
47
0
  {
48
0
    libcerror_error_set(
49
0
     error,
50
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
51
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
52
0
     "%s: invalid metadata block.",
53
0
     function );
54
55
0
    return( -1 );
56
0
  }
57
875
  if( *metadata_block != NULL )
58
0
  {
59
0
    libcerror_error_set(
60
0
     error,
61
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
62
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
63
0
     "%s: invalid metadata block value already set.",
64
0
     function );
65
66
0
    return( -1 );
67
0
  }
68
875
  *metadata_block = memory_allocate_structure(
69
875
                     libfvde_metadata_block_t );
70
71
875
  if( *metadata_block == NULL )
72
0
  {
73
0
    libcerror_error_set(
74
0
     error,
75
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
76
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
77
0
     "%s: unable to create metadata block.",
78
0
     function );
79
80
0
    goto on_error;
81
0
  }
82
875
  if( memory_set(
83
875
       *metadata_block,
84
875
       0,
85
875
       sizeof( libfvde_metadata_block_t ) ) == NULL )
86
0
  {
87
0
    libcerror_error_set(
88
0
     error,
89
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
90
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
91
0
     "%s: unable to clear metadata block.",
92
0
     function );
93
94
0
    goto on_error;
95
0
  }
96
875
  return( 1 );
97
98
0
on_error:
99
0
  if( *metadata_block != NULL )
100
0
  {
101
0
    memory_free(
102
0
     *metadata_block );
103
104
0
    *metadata_block = NULL;
105
0
  }
106
0
  return( -1 );
107
875
}
108
109
/* Frees a metadata block
110
 * Returns 1 if successful or -1 on error
111
 */
112
int libfvde_metadata_block_free(
113
     libfvde_metadata_block_t **metadata_block,
114
     libcerror_error_t **error )
115
875
{
116
875
  static char *function = "libfvde_metadata_block_free";
117
118
875
  if( metadata_block == NULL )
119
0
  {
120
0
    libcerror_error_set(
121
0
     error,
122
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
123
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
124
0
     "%s: invalid metadata block.",
125
0
     function );
126
127
0
    return( -1 );
128
0
  }
129
875
  if( *metadata_block != NULL )
130
875
  {
131
    /* The data is referenced and freed elsewhere */
132
875
    memory_free(
133
875
     *metadata_block );
134
135
875
    *metadata_block = NULL;
136
875
  }
137
875
  return( 1 );
138
875
}
139
140
/* Checks if a buffer containing the metadata block data is filled with same value bytes (empty-block)
141
 * Returns 1 if a pattern was found, 0 if not or -1 on error
142
 */
143
int libfvde_metadata_block_check_for_empty_block(
144
     const uint8_t *data,
145
     size_t data_size,
146
     libcerror_error_t **error )
147
0
{
148
0
  libfvde_aligned_t *aligned_data_index = NULL;
149
0
  libfvde_aligned_t *aligned_data_start = NULL;
150
0
  uint8_t *data_index                   = NULL;
151
0
  uint8_t *data_start                   = NULL;
152
0
  static char *function                 = "libfvde_metadata_block_check_for_empty_block";
153
154
0
  if( data == NULL )
155
0
  {
156
0
    libcerror_error_set(
157
0
     error,
158
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
159
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
160
0
     "%s: invalid data.",
161
0
     function );
162
163
0
    return( -1 );
164
0
  }
165
0
  if( data_size > (size_t) SSIZE_MAX )
166
0
  {
167
0
    libcerror_error_set(
168
0
     error,
169
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
170
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
171
0
     "%s: invalid data size value exceeds maximum.",
172
0
     function );
173
174
0
    return( -1 );
175
0
  }
176
0
  data_start = (uint8_t *) data;
177
0
  data_index = (uint8_t *) data + 1;
178
0
  data_size -= 1;
179
180
  /* Only optimize for data larger than the alignment
181
   */
182
0
  if( data_size > ( 2 * sizeof( libfvde_aligned_t ) ) )
183
0
  {
184
    /* Align the data start
185
     */
186
0
    while( ( (intptr_t) data_start % sizeof( libfvde_aligned_t ) ) != 0 )
187
0
    {
188
0
      if( *data_start != *data_index )
189
0
      {
190
0
        return( 0 );
191
0
      }
192
0
      data_start += 1;
193
0
      data_index += 1;
194
0
      data_size  -= 1;
195
0
    }
196
    /* Align the data index
197
     */
198
0
    while( ( (intptr_t) data_index % sizeof( libfvde_aligned_t ) ) != 0 )
199
0
    {
200
0
      if( *data_start != *data_index )
201
0
      {
202
0
        return( 0 );
203
0
      }
204
0
      data_index += 1;
205
0
      data_size  -= 1;
206
0
    }
207
0
    aligned_data_start = (libfvde_aligned_t *) data_start;
208
0
    aligned_data_index = (libfvde_aligned_t *) data_index;
209
210
0
    while( data_size > sizeof( libfvde_aligned_t ) )
211
0
    {
212
0
      if( *aligned_data_start != *aligned_data_index )
213
0
      {
214
0
        return( 0 );
215
0
      }
216
0
      aligned_data_index += 1;
217
0
      data_size          -= sizeof( libfvde_aligned_t );
218
0
    }
219
0
    data_index = (uint8_t *) aligned_data_index;
220
0
  }
221
0
  while( data_size != 0 )
222
0
  {
223
0
    if( *data_start != *data_index )
224
0
    {
225
0
      return( 0 );
226
0
    }
227
0
    data_index += 1;
228
0
    data_size  -= 1;
229
0
  }
230
0
  return( 1 );
231
0
}
232
233
/* Reads the metadata block data
234
 * Returns 1 if successful, 0 if block is empty or -1 on error
235
 */
236
int libfvde_metadata_block_read_data(
237
     libfvde_metadata_block_t *metadata_block,
238
     const uint8_t *block_data,
239
     size_t block_data_size,
240
     libcerror_error_t **error )
241
875
{
242
875
  static char *function        = "libfvde_metadata_block_read_data";
243
875
  uint32_t block_size          = 0;
244
875
  uint32_t calculated_checksum = 0;
245
875
  uint32_t initial_value       = 0;
246
875
  uint32_t stored_checksum     = 0;
247
875
  uint16_t version             = 0;
248
249
#if defined( HAVE_DEBUG_OUTPUT )
250
  uint64_t value_64bit         = 0;
251
  uint32_t value_32bit         = 0;
252
#endif
253
254
875
  if( metadata_block == NULL )
255
0
  {
256
0
    libcerror_error_set(
257
0
     error,
258
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
259
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
260
0
     "%s: invalid metadata block.",
261
0
     function );
262
263
0
    return( -1 );
264
0
  }
265
875
  if( block_data == NULL )
266
0
  {
267
0
    libcerror_error_set(
268
0
     error,
269
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
270
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
271
0
     "%s: invalid block data.",
272
0
     function );
273
274
0
    return( -1 );
275
0
  }
276
875
  if( ( block_data_size < sizeof( fvde_metadata_block_header_t ) )
277
875
   || ( block_data_size > (size_t) SSIZE_MAX ) )
278
0
  {
279
0
    libcerror_error_set(
280
0
     error,
281
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
282
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
283
0
     "%s: block data size value out of bounds.",
284
0
     function );
285
286
0
    return( -1 );
287
0
  }
288
#if defined( HAVE_DEBUG_OUTPUT )
289
  if( libcnotify_verbose != 0 )
290
  {
291
    libcnotify_printf(
292
     "%s: header data:\n",
293
     function );
294
    libcnotify_print_data(
295
     block_data,
296
     sizeof( fvde_metadata_block_header_t ),
297
     0 );
298
  }
299
#endif
300
  /* Check if metadata block starts with: LVFwiped
301
   */
302
875
  if( ( block_data[ 0 ] == (uint8_t) 'L' )
303
875
   && ( block_data[ 1 ] == (uint8_t) 'V' )
304
875
   && ( block_data[ 2 ] == (uint8_t) 'F' )
305
875
   && ( block_data[ 3 ] == (uint8_t) 'w' )
306
875
   && ( block_data[ 4 ] == (uint8_t) 'i' )
307
875
   && ( block_data[ 5 ] == (uint8_t) 'p' )
308
875
   && ( block_data[ 6 ] == (uint8_t) 'e' )
309
875
   && ( block_data[ 7 ] == (uint8_t) 'd' ) )
310
692
  {
311
692
    metadata_block->is_lvf_wiped = 1;
312
692
  }
313
183
  else
314
183
  {
315
183
    metadata_block->is_lvf_wiped = 0;
316
183
  }
317
875
  byte_stream_copy_to_uint32_little_endian(
318
875
   ( (fvde_metadata_block_header_t *) block_data )->checksum,
319
875
   stored_checksum );
320
321
875
  byte_stream_copy_to_uint32_little_endian(
322
875
   ( (fvde_metadata_block_header_t *) block_data )->initial_value,
323
875
   initial_value );
324
325
875
  byte_stream_copy_to_uint16_little_endian(
326
875
   ( (fvde_metadata_block_header_t *) block_data )->version,
327
875
   version );
328
329
875
  byte_stream_copy_to_uint16_little_endian(
330
875
   ( (fvde_metadata_block_header_t *) block_data )->type,
331
875
   metadata_block->type );
332
333
875
  byte_stream_copy_to_uint32_little_endian(
334
875
   ( (fvde_metadata_block_header_t *) block_data )->serial_number,
335
875
   metadata_block->serial_number );
336
337
875
  byte_stream_copy_to_uint64_little_endian(
338
875
   ( (fvde_metadata_block_header_t *) block_data )->transaction_identifier,
339
875
   metadata_block->transaction_identifier );
340
341
875
  byte_stream_copy_to_uint64_little_endian(
342
875
   ( (fvde_metadata_block_header_t *) block_data )->object_identifier,
343
875
   metadata_block->object_identifier );
344
345
875
  byte_stream_copy_to_uint64_little_endian(
346
875
   ( (fvde_metadata_block_header_t *) block_data )->number,
347
875
   metadata_block->number );
348
349
875
  byte_stream_copy_to_uint32_little_endian(
350
875
   ( (fvde_metadata_block_header_t *) block_data )->block_size,
351
875
   block_size );
352
353
#if defined( HAVE_DEBUG_OUTPUT )
354
  if( libcnotify_verbose != 0 )
355
  {
356
    if( metadata_block->is_lvf_wiped == 0 )
357
    {
358
      libcnotify_printf(
359
       "%s: checksum\t\t\t\t: 0x%08" PRIx32 "\n",
360
       function,
361
       stored_checksum );
362
363
      libcnotify_printf(
364
       "%s: initial value\t\t\t\t: 0x%08" PRIx32 "\n",
365
       function,
366
       initial_value );
367
    }
368
    else
369
    {
370
      libcnotify_printf(
371
       "%s: signature\t\t\t\t: LVFwiped\n",
372
       function );
373
    }
374
    libcnotify_printf(
375
     "%s: version\t\t\t\t: %" PRIu16 "\n",
376
     function,
377
     version );
378
379
    libcnotify_printf(
380
     "%s: type\t\t\t\t\t: 0x%04" PRIx16 "\n",
381
     function,
382
     metadata_block->type );
383
384
    libcnotify_printf(
385
     "%s: serial number\t\t\t\t: 0x%08" PRIx32 "\n",
386
     function,
387
     metadata_block->serial_number );
388
389
    libcnotify_printf(
390
     "%s: transaction identifier\t\t: %" PRIu64 "\n",
391
     function,
392
     metadata_block->transaction_identifier );
393
394
    libcnotify_printf(
395
     "%s: object identifier\t\t\t: %" PRIu64 "\n",
396
     function,
397
     metadata_block->object_identifier );
398
399
    libcnotify_printf(
400
     "%s: number\t\t\t\t: %" PRIu64 "\n",
401
     function,
402
     metadata_block->number );
403
404
    byte_stream_copy_to_uint64_little_endian(
405
     ( (fvde_metadata_block_header_t *) block_data )->unknown5,
406
     value_64bit );
407
    libcnotify_printf(
408
     "%s: unknown5\t\t\t\t: 0x%08" PRIx64 "\n",
409
     function,
410
     value_64bit );
411
412
    libcnotify_printf(
413
     "%s: size\t\t\t\t\t: %" PRIu32 "\n",
414
     function,
415
     block_size );
416
417
    byte_stream_copy_to_uint32_little_endian(
418
     ( (fvde_metadata_block_header_t *) block_data )->unknown6,
419
     value_32bit );
420
    libcnotify_printf(
421
     "%s: unknown6\t\t\t\t: 0x%08" PRIx32 "\n",
422
     function,
423
     value_32bit );
424
425
    byte_stream_copy_to_uint64_little_endian(
426
     ( (fvde_metadata_block_header_t *) block_data )->unknown7,
427
     value_64bit );
428
    libcnotify_printf(
429
     "%s: unknown7\t\t\t\t: 0x%08" PRIx64 "\n",
430
     function,
431
     value_64bit );
432
433
    libcnotify_printf(
434
     "\n" );
435
  }
436
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
437
438
875
  if( block_size != 8192 )
439
79
  {
440
79
    libcerror_error_set(
441
79
     error,
442
79
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
443
79
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
444
79
     "%s: unsupported block size: %" PRIu64 ".",
445
79
     function,
446
79
     block_size );
447
448
79
    return( -1 );
449
79
  }
450
796
  if( metadata_block->is_lvf_wiped == 0 )
451
106
  {
452
106
    if( initial_value != 0xffffffffUL )
453
68
    {
454
68
      libcerror_error_set(
455
68
       error,
456
68
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
457
68
       LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
458
68
       "%s: unsupported initial value: 0x%08" PRIx32 ".",
459
68
       function,
460
68
       initial_value );
461
462
68
      return( -1 );
463
68
    }
464
38
    if( libfvde_checksum_calculate_weak_crc32(
465
38
         &calculated_checksum,
466
38
         &( block_data[ 8 ] ),
467
38
         8184,
468
38
         initial_value,
469
38
         error ) != 1 )
470
0
    {
471
0
      libcerror_error_set(
472
0
       error,
473
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
474
0
       LIBCERROR_RUNTIME_ERROR_GENERIC,
475
0
       "%s: unable to calculate weak CRC-32.",
476
0
       function );
477
478
0
      return( -1 );
479
0
    }
480
38
    if( stored_checksum != calculated_checksum )
481
36
    {
482
36
      libcerror_error_set(
483
36
       error,
484
36
       LIBCERROR_ERROR_DOMAIN_INPUT,
485
36
       LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH,
486
36
       "%s: mismatch in checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).",
487
36
       function,
488
36
       stored_checksum,
489
36
       calculated_checksum );
490
491
36
      return( -1 );
492
36
    }
493
38
  }
494
692
  metadata_block->data      = block_data + sizeof( fvde_metadata_block_header_t );
495
692
  metadata_block->data_size = block_data_size - sizeof( fvde_metadata_block_header_t );
496
497
#if defined( HAVE_DEBUG_OUTPUT )
498
  if( libcnotify_verbose != 0 )
499
  {
500
    libcnotify_printf(
501
     "%s: data:\n",
502
     function );
503
    libcnotify_print_data(
504
     metadata_block->data,
505
     metadata_block->data_size,
506
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
507
  }
508
#endif
509
692
  return( 1 );
510
796
}
511