Coverage Report

Created: 2025-06-22 07:35

/src/libvsgpt/libvsgpt/libvsgpt_partition_table_header.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * The partition table header functions
3
 *
4
 * Copyright (C) 2019-2024, Joachim Metz <joachim.metz@gmail.com>
5
 *
6
 * Refer to AUTHORS for acknowledgements.
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
#include <common.h>
23
#include <byte_stream.h>
24
#include <memory.h>
25
#include <types.h>
26
27
#include "libvsgpt_checksum.h"
28
#include "libvsgpt_debug.h"
29
#include "libvsgpt_libbfio.h"
30
#include "libvsgpt_libcerror.h"
31
#include "libvsgpt_libcnotify.h"
32
#include "libvsgpt_libfguid.h"
33
#include "libvsgpt_partition_table_header.h"
34
35
#include "vsgpt_partition_table.h"
36
37
/* Creates a partition table header
38
 * Make sure the value partition_table_header is referencing, is set to NULL
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libvsgpt_partition_table_header_initialize(
42
     libvsgpt_partition_table_header_t **partition_table_header,
43
     libcerror_error_t **error )
44
3.58k
{
45
3.58k
  static char *function = "libvsgpt_partition_table_header_initialize";
46
47
3.58k
  if( partition_table_header == NULL )
48
0
  {
49
0
    libcerror_error_set(
50
0
     error,
51
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
52
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
53
0
     "%s: invalid partition table header.",
54
0
     function );
55
56
0
    return( -1 );
57
0
  }
58
3.58k
  if( *partition_table_header != NULL )
59
0
  {
60
0
    libcerror_error_set(
61
0
     error,
62
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
63
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
64
0
     "%s: invalid partition table header value already set.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
3.58k
  *partition_table_header = memory_allocate_structure(
70
3.58k
                             libvsgpt_partition_table_header_t );
71
72
3.58k
  if( *partition_table_header == NULL )
73
0
  {
74
0
    libcerror_error_set(
75
0
     error,
76
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
77
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
78
0
     "%s: unable to create partition table header.",
79
0
     function );
80
81
0
    goto on_error;
82
0
  }
83
3.58k
  if( memory_set(
84
3.58k
       *partition_table_header,
85
3.58k
       0,
86
3.58k
       sizeof( libvsgpt_partition_table_header_t ) ) == NULL )
87
0
  {
88
0
    libcerror_error_set(
89
0
     error,
90
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
91
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
92
0
     "%s: unable to clear partition table header.",
93
0
     function );
94
95
0
    goto on_error;
96
0
  }
97
3.58k
  return( 1 );
98
99
0
on_error:
100
0
  if( *partition_table_header != NULL )
101
0
  {
102
0
    memory_free(
103
0
     *partition_table_header );
104
105
0
    *partition_table_header = NULL;
106
0
  }
107
0
  return( -1 );
108
3.58k
}
109
110
/* Frees a partition table header
111
 * Returns 1 if successful or -1 on error
112
 */
113
int libvsgpt_partition_table_header_free(
114
     libvsgpt_partition_table_header_t **partition_table_header,
115
     libcerror_error_t **error )
116
3.58k
{
117
3.58k
  static char *function = "libvsgpt_partition_table_header_free";
118
119
3.58k
  if( partition_table_header == NULL )
120
0
  {
121
0
    libcerror_error_set(
122
0
     error,
123
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
124
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
125
0
     "%s: invalid partition table header.",
126
0
     function );
127
128
0
    return( -1 );
129
0
  }
130
3.58k
  if( *partition_table_header != NULL )
131
3.58k
  {
132
3.58k
    memory_free(
133
3.58k
     *partition_table_header );
134
135
3.58k
    *partition_table_header = NULL;
136
3.58k
  }
137
3.58k
  return( 1 );
138
3.58k
}
139
140
/* Reads a partition table header
141
 * Returns 1 if successful, 0 if signature does not match or -1 on error
142
 */
143
int libvsgpt_partition_table_header_read_data(
144
     libvsgpt_partition_table_header_t *partition_table_header,
145
     const uint8_t *data,
146
     size_t data_size,
147
     libcerror_error_t **error )
148
3.52k
{
149
3.52k
  uint8_t empty_checksum_data[ 4 ] = { 0, 0, 0, 0 };
150
151
3.52k
  static char *function            = "libvsgpt_partition_table_header_read_data";
152
3.52k
  uint32_t calculated_checksum     = 0;
153
3.52k
  uint32_t header_data_size        = 0;
154
3.52k
  uint32_t stored_checksum         = 0;
155
3.52k
  uint16_t major_format_version    = 0;
156
3.52k
  uint16_t minor_format_version    = 0;
157
158
3.52k
  if( partition_table_header == NULL )
159
0
  {
160
0
    libcerror_error_set(
161
0
     error,
162
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
163
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
164
0
     "%s: invalid partition table header.",
165
0
     function );
166
167
0
    return( -1 );
168
0
  }
169
3.52k
  if( data == NULL )
170
0
  {
171
0
    libcerror_error_set(
172
0
     error,
173
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
174
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
175
0
     "%s: invalid data.",
176
0
     function );
177
178
0
    return( -1 );
179
0
  }
180
3.52k
  if( ( data_size < sizeof( vsgpt_partition_table_header_t ) )
181
3.52k
   || ( data_size > (size_t) SSIZE_MAX ) )
182
0
  {
183
0
    libcerror_error_set(
184
0
     error,
185
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
186
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
187
0
     "%s: data size value out of bounds.",
188
0
     function );
189
190
0
    return( -1 );
191
0
  }
192
#if defined( HAVE_DEBUG_OUTPUT )
193
  if( libcnotify_verbose != 0 )
194
  {
195
    libcnotify_printf(
196
     "%s: partition table header data:\n",
197
     function );
198
    libcnotify_print_data(
199
     data,
200
     data_size,
201
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
202
  }
203
#endif
204
3.52k
  if( memory_compare(
205
3.52k
       ( (vsgpt_partition_table_header_t *) data )->signature,
206
3.52k
       "EFI PART",
207
3.52k
       8 ) != 0 )
208
196
  {
209
196
    return( 0 );
210
196
  }
211
3.32k
  byte_stream_copy_to_uint16_little_endian(
212
3.32k
   ( (vsgpt_partition_table_header_t *) data )->major_format_version,
213
3.32k
   major_format_version );
214
215
3.32k
  byte_stream_copy_to_uint16_little_endian(
216
3.32k
   ( (vsgpt_partition_table_header_t *) data )->minor_format_version,
217
3.32k
   minor_format_version );
218
219
3.32k
  byte_stream_copy_to_uint32_little_endian(
220
3.32k
   ( (vsgpt_partition_table_header_t *) data )->header_data_size,
221
3.32k
   header_data_size );
222
223
3.32k
  byte_stream_copy_to_uint32_little_endian(
224
3.32k
   ( (vsgpt_partition_table_header_t *) data )->header_data_checksum,
225
3.32k
   stored_checksum );
226
227
3.32k
  byte_stream_copy_to_uint64_little_endian(
228
3.32k
   ( (vsgpt_partition_table_header_t *) data )->header_block_number,
229
3.32k
   partition_table_header->partition_header_block_number );
230
231
3.32k
  byte_stream_copy_to_uint64_little_endian(
232
3.32k
   ( (vsgpt_partition_table_header_t *) data )->backup_header_block_number,
233
3.32k
   partition_table_header->backup_partition_header_block_number );
234
235
3.32k
  byte_stream_copy_to_uint64_little_endian(
236
3.32k
   ( (vsgpt_partition_table_header_t *) data )->area_start_block_number,
237
3.32k
   partition_table_header->partition_area_start_block_number );
238
239
3.32k
  byte_stream_copy_to_uint64_little_endian(
240
3.32k
   ( (vsgpt_partition_table_header_t *) data )->area_end_block_number,
241
3.32k
   partition_table_header->partition_area_end_block_number );
242
243
3.32k
  if( memory_copy(
244
3.32k
       partition_table_header->disk_identifier,
245
3.32k
       ( (vsgpt_partition_table_header_t *) data )->disk_identifier,
246
3.32k
       16 ) == NULL )
247
0
  {
248
0
    libcerror_error_set(
249
0
     error,
250
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
251
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
252
0
     "%s: unable to copy disk identifier.",
253
0
     function );
254
255
0
    return( -1 );
256
0
  }
257
3.32k
  byte_stream_copy_to_uint64_little_endian(
258
3.32k
   ( (vsgpt_partition_table_header_t *) data )->entries_start_block_number,
259
3.32k
   partition_table_header->partition_entries_start_block_number );
260
261
3.32k
  byte_stream_copy_to_uint32_little_endian(
262
3.32k
   ( (vsgpt_partition_table_header_t *) data )->number_of_entries,
263
3.32k
   partition_table_header->number_of_partition_entries );
264
265
3.32k
  byte_stream_copy_to_uint32_little_endian(
266
3.32k
   ( (vsgpt_partition_table_header_t *) data )->entry_data_size,
267
3.32k
   partition_table_header->partition_entry_data_size );
268
269
3.32k
  byte_stream_copy_to_uint32_little_endian(
270
3.32k
   ( (vsgpt_partition_table_header_t *) data )->entries_data_checksum,
271
3.32k
   partition_table_header->partition_entries_data_checksum );
272
273
#if defined( HAVE_DEBUG_OUTPUT )
274
  if( libcnotify_verbose != 0 )
275
  {
276
    libcnotify_printf(
277
     "%s: signature\t\t\t: %c%c%c%c%c%c%c%c\n",
278
     function,
279
     ( (vsgpt_partition_table_header_t *) data )->signature[ 0 ],
280
     ( (vsgpt_partition_table_header_t *) data )->signature[ 1 ],
281
     ( (vsgpt_partition_table_header_t *) data )->signature[ 2 ],
282
     ( (vsgpt_partition_table_header_t *) data )->signature[ 3 ],
283
     ( (vsgpt_partition_table_header_t *) data )->signature[ 4 ],
284
     ( (vsgpt_partition_table_header_t *) data )->signature[ 5 ],
285
     ( (vsgpt_partition_table_header_t *) data )->signature[ 6 ],
286
     ( (vsgpt_partition_table_header_t *) data )->signature[ 7 ] );
287
288
    libcnotify_printf(
289
     "%s: format version\t\t: %" PRIu16 ".%" PRIu16 "\n",
290
     function,
291
     major_format_version,
292
     minor_format_version );
293
294
    libcnotify_printf(
295
     "%s: header data size\t\t: %" PRIu32 "\n",
296
     function,
297
     header_data_size );
298
299
    libcnotify_printf(
300
     "%s: header data checksum\t\t: 0x%08" PRIx32 "\n",
301
     function,
302
     stored_checksum );
303
304
    libcnotify_printf(
305
     "%s: header block number\t\t: %" PRIu64 "\n",
306
     function,
307
     partition_table_header->partition_header_block_number );
308
309
    libcnotify_printf(
310
     "%s: backup header block number\t: %" PRIu64 "\n",
311
     function,
312
     partition_table_header->backup_partition_header_block_number );
313
314
    libcnotify_printf(
315
     "%s: area start block number\t: %" PRIu64 "\n",
316
     function,
317
     partition_table_header->partition_area_start_block_number );
318
319
    libcnotify_printf(
320
     "%s: area end block number\t: %" PRIu64 "\n",
321
     function,
322
     partition_table_header->partition_area_end_block_number );
323
324
    if( libvsgpt_debug_print_guid_value(
325
         function,
326
         "disk identifier\t\t",
327
         ( (vsgpt_partition_table_header_t *) data )->disk_identifier,
328
         16,
329
         LIBFGUID_ENDIAN_LITTLE,
330
         LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
331
         error ) != 1 )
332
    {
333
      libcerror_error_set(
334
       error,
335
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
336
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
337
       "%s: unable to print GUID value.",
338
       function );
339
340
      return( -1 );
341
    }
342
    libcnotify_printf(
343
     "%s: entries start block number\t: %" PRIu64 "\n",
344
     function,
345
     partition_table_header->partition_entries_start_block_number );
346
347
    libcnotify_printf(
348
     "%s: number of entries\t\t: %" PRIu32 "\n",
349
     function,
350
     partition_table_header->number_of_partition_entries );
351
352
    libcnotify_printf(
353
     "%s: entry data size\t\t: %" PRIu32 "\n",
354
     function,
355
     partition_table_header->partition_entry_data_size );
356
357
    libcnotify_printf(
358
     "%s: entries data checksum\t: 0x%08" PRIx32 "\n",
359
     function,
360
     partition_table_header->partition_entries_data_checksum );
361
362
    libcnotify_printf(
363
     "\n" );
364
  }
365
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
366
367
3.32k
  if( ( header_data_size < sizeof( vsgpt_partition_table_header_t ) )
368
3.32k
   || ( header_data_size > data_size ) )
369
132
  {
370
132
    libcerror_error_set(
371
132
     error,
372
132
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
373
132
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
374
132
     "%s: header data size value out of bounds.",
375
132
     function );
376
377
132
    return( -1 );
378
132
  }
379
3.19k
  if( libvsgpt_checksum_calculate_crc32(
380
3.19k
       &calculated_checksum,
381
3.19k
       data,
382
3.19k
       16,
383
3.19k
       0,
384
3.19k
       error ) != 1 )
385
0
  {
386
0
    libcerror_error_set(
387
0
     error,
388
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
389
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
390
0
     "%s: unable to calculate CRC-32.",
391
0
     function );
392
393
0
    return( -1 );
394
0
  }
395
3.19k
  if( libvsgpt_checksum_calculate_crc32(
396
3.19k
       &calculated_checksum,
397
3.19k
       empty_checksum_data,
398
3.19k
       4,
399
3.19k
       calculated_checksum,
400
3.19k
       error ) != 1 )
401
0
  {
402
0
    libcerror_error_set(
403
0
     error,
404
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
405
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
406
0
     "%s: unable to calculate CRC-32.",
407
0
     function );
408
409
0
    return( -1 );
410
0
  }
411
3.19k
  if( libvsgpt_checksum_calculate_crc32(
412
3.19k
       &calculated_checksum,
413
3.19k
       &( data[ 20 ] ),
414
3.19k
       header_data_size - 20,
415
3.19k
       calculated_checksum,
416
3.19k
       error ) != 1 )
417
0
  {
418
0
    libcerror_error_set(
419
0
     error,
420
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
421
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
422
0
     "%s: unable to calculate CRC-32.",
423
0
     function );
424
425
0
    return( -1 );
426
0
  }
427
3.19k
  if( ( stored_checksum != 0 )
428
3.19k
   && ( stored_checksum != calculated_checksum ) )
429
298
  {
430
#if defined( HAVE_DEBUG_OUTPUT )
431
    if( libcnotify_verbose != 0 )
432
    {
433
      libcnotify_printf(
434
       "%s: mismatch in checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).\n",
435
       function,
436
       stored_checksum,
437
       calculated_checksum );
438
    }
439
#endif
440
298
    partition_table_header->is_corrupt = 1;
441
298
  }
442
3.19k
  if( ( major_format_version != 1 )
443
3.19k
   || ( minor_format_version != 0 ) )
444
174
  {
445
#if defined( HAVE_DEBUG_OUTPUT )
446
    if( libcnotify_verbose != 0 )
447
    {
448
      libcnotify_printf(
449
       "%s: unsupported format version: %" PRIu16 ".%" PRIu16 "\n",
450
       function,
451
       major_format_version,
452
       minor_format_version );
453
    }
454
#endif
455
174
    partition_table_header->is_corrupt = 1;
456
174
  }
457
3.19k
  return( 1 );
458
3.19k
}
459
460
/* Reads a partition table header
461
 * Returns 1 if successful, 0 if signature does not match or -1 on error
462
 */
463
int libvsgpt_partition_table_header_read_file_io_handle(
464
     libvsgpt_partition_table_header_t *partition_table_header,
465
     libbfio_handle_t *file_io_handle,
466
     off64_t file_offset,
467
     libcerror_error_t **error )
468
3.77k
{
469
3.77k
  uint8_t block_data[ 512 ];
470
471
3.77k
  static char *function = "libvsgpt_partition_table_header_read_file_io_handle";
472
3.77k
  ssize_t read_count    = 0;
473
3.77k
  int result            = 0;
474
475
3.77k
  if( partition_table_header == NULL )
476
0
  {
477
0
    libcerror_error_set(
478
0
     error,
479
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
480
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
481
0
     "%s: invalid partition table header.",
482
0
     function );
483
484
0
    return( -1 );
485
0
  }
486
#if defined( HAVE_DEBUG_OUTPUT )
487
  if( libcnotify_verbose != 0 )
488
  {
489
    libcnotify_printf(
490
     "%s: reading partition table header at offset: %" PRIu64 " (0x%08" PRIx64 ").\n",
491
     function,
492
     file_offset,
493
     file_offset );
494
  }
495
#endif
496
3.77k
  read_count = libbfio_handle_read_buffer_at_offset(
497
3.77k
                file_io_handle,
498
3.77k
                block_data,
499
3.77k
                512,
500
3.77k
                file_offset,
501
3.77k
                error );
502
503
3.77k
  if( read_count != (ssize_t) 512 )
504
245
  {
505
245
    libcerror_error_set(
506
245
     error,
507
245
     LIBCERROR_ERROR_DOMAIN_IO,
508
245
     LIBCERROR_IO_ERROR_READ_FAILED,
509
245
     "%s: unable to read partition table header data at offset: %" PRIu64 " (0x%08" PRIx64 ").",
510
245
     function,
511
245
     file_offset,
512
245
     file_offset );
513
514
245
    return( -1 );
515
245
  }
516
3.52k
  result = libvsgpt_partition_table_header_read_data(
517
3.52k
            partition_table_header,
518
3.52k
            block_data,
519
3.52k
            512,
520
3.52k
            error );
521
522
3.52k
  if( result == -1 )
523
132
  {
524
132
    libcerror_error_set(
525
132
     error,
526
132
     LIBCERROR_ERROR_DOMAIN_IO,
527
132
     LIBCERROR_IO_ERROR_READ_FAILED,
528
132
     "%s: unable to read partition table header.",
529
132
     function );
530
531
132
    return( -1 );
532
132
  }
533
3.39k
  return( result );
534
3.52k
}
535
536
/* Retrieves the disk identifier
537
 * The identifier is a GUID stored in little-endian and is 16 bytes of size
538
 * Returns 1 if successful or -1 on error
539
 */
540
int libvsgpt_partition_table_header_get_disk_identifier(
541
     libvsgpt_partition_table_header_t *partition_table_header,
542
     uint8_t *guid_data,
543
     size_t guid_data_size,
544
     libcerror_error_t **error )
545
0
{
546
0
  static char *function = "libvsgpt_partition_table_header_get_disk_identifier";
547
548
0
  if( partition_table_header == NULL )
549
0
  {
550
0
    libcerror_error_set(
551
0
     error,
552
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
553
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
554
0
     "%s: invalid partition table header.",
555
0
     function );
556
557
0
    return( -1 );
558
0
  }
559
0
  if( guid_data == NULL )
560
0
  {
561
0
    libcerror_error_set(
562
0
     error,
563
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
564
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
565
0
     "%s: invalid GUID data.",
566
0
     function );
567
568
0
    return( -1 );
569
0
  }
570
0
  if( ( guid_data_size < 16 )
571
0
   || ( guid_data_size > (size_t) SSIZE_MAX ) )
572
0
  {
573
0
    libcerror_error_set(
574
0
     error,
575
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
576
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
577
0
     "%s: invalid GUID data size value out of bounds.",
578
0
     function );
579
580
0
    return( -1 );
581
0
  }
582
0
  if( memory_copy(
583
0
       guid_data,
584
0
       partition_table_header->disk_identifier,
585
0
       16 ) == NULL )
586
0
  {
587
0
    libcerror_error_set(
588
0
     error,
589
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
590
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
591
0
     "%s: unable to copy disk identifier.",
592
0
     function );
593
594
0
    return( -1 );
595
0
  }
596
0
  return( 1 );
597
0
}
598