Coverage Report

Created: 2024-10-02 06:58

/src/libmodi/libmodi/libmodi_sparse_image_header.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Sparse image header functions
3
 *
4
 * Copyright (C) 2012-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 "libmodi_io_handle.h"
28
#include "libmodi_libbfio.h"
29
#include "libmodi_libcerror.h"
30
#include "libmodi_libcnotify.h"
31
#include "libmodi_sparse_image_header.h"
32
33
#include "modi_sparse_image_header.h"
34
35
/* Creates a sparse image header
36
 * Make sure the value sparse_image_header is referencing, is set to NULL
37
 * Returns 1 if successful or -1 on error
38
 */
39
int libmodi_sparse_image_header_initialize(
40
     libmodi_sparse_image_header_t **sparse_image_header,
41
     libcerror_error_t **error )
42
344
{
43
344
  static char *function = "libmodi_sparse_image_header_initialize";
44
45
344
  if( sparse_image_header == NULL )
46
0
  {
47
0
    libcerror_error_set(
48
0
     error,
49
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
50
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
51
0
     "%s: invalid sparse image header.",
52
0
     function );
53
54
0
    return( -1 );
55
0
  }
56
344
  if( *sparse_image_header != NULL )
57
0
  {
58
0
    libcerror_error_set(
59
0
     error,
60
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
61
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
62
0
     "%s: invalid sparse image header value already set.",
63
0
     function );
64
65
0
    return( -1 );
66
0
  }
67
344
  *sparse_image_header = memory_allocate_structure(
68
344
                          libmodi_sparse_image_header_t );
69
70
344
  if( *sparse_image_header == NULL )
71
0
  {
72
0
    libcerror_error_set(
73
0
     error,
74
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
75
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
76
0
     "%s: unable to create sparse image header.",
77
0
     function );
78
79
0
    goto on_error;
80
0
  }
81
344
  if( memory_set(
82
344
       *sparse_image_header,
83
344
       0,
84
344
       sizeof( libmodi_sparse_image_header_t ) ) == NULL )
85
0
  {
86
0
    libcerror_error_set(
87
0
     error,
88
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
89
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
90
0
     "%s: unable to clear sparse image header.",
91
0
     function );
92
93
0
    goto on_error;
94
0
  }
95
344
  return( 1 );
96
97
0
on_error:
98
0
  if( *sparse_image_header != NULL )
99
0
  {
100
0
    memory_free(
101
0
     *sparse_image_header );
102
103
0
    *sparse_image_header = NULL;
104
0
  }
105
0
  return( -1 );
106
344
}
107
108
/* Frees a sparse image header
109
 * Returns 1 if successful or -1 on error
110
 */
111
int libmodi_sparse_image_header_free(
112
     libmodi_sparse_image_header_t **sparse_image_header,
113
     libcerror_error_t **error )
114
344
{
115
344
  static char *function = "libmodi_sparse_image_header_free";
116
117
344
  if( sparse_image_header == NULL )
118
0
  {
119
0
    libcerror_error_set(
120
0
     error,
121
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
122
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
123
0
     "%s: invalid sparse image header.",
124
0
     function );
125
126
0
    return( -1 );
127
0
  }
128
344
  if( *sparse_image_header != NULL )
129
344
  {
130
344
    if( ( *sparse_image_header )->band_references != NULL )
131
22
    {
132
22
      memory_free(
133
22
       ( *sparse_image_header )->band_references );
134
22
    }
135
344
    memory_free(
136
344
     *sparse_image_header );
137
138
344
    *sparse_image_header = NULL;
139
344
  }
140
344
  return( 1 );
141
344
}
142
143
/* Reads a sparse image header
144
 * Returns 1 if successful, 0 if the signature does not match or -1 on error
145
 */
146
int libmodi_sparse_image_header_read_data(
147
     libmodi_sparse_image_header_t *sparse_image_header,
148
     const uint8_t *data,
149
     size_t data_size,
150
     libcerror_error_t **error )
151
344
{
152
344
  static char *function          = "libmodi_sparse_image_header_read_data";
153
344
  size_t bands_table_data_size   = 0;
154
344
  size_t data_offset             = 0;
155
344
  uint32_t bands_table_index     = 0;
156
344
  uint32_t bands_table_reference = 0;
157
158
#if defined( HAVE_DEBUG_OUTPUT )
159
  uint32_t value_32bit           = 0;
160
#endif
161
162
344
  if( sparse_image_header == NULL )
163
0
  {
164
0
    libcerror_error_set(
165
0
     error,
166
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
167
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
168
0
     "%s: invalid sparse image header.",
169
0
     function );
170
171
0
    return( -1 );
172
0
  }
173
344
  if( sparse_image_header->band_references != NULL )
174
0
  {
175
0
    libcerror_error_set(
176
0
     error,
177
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
178
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
179
0
     "%s: invalid sparse image header - band references value already set.",
180
0
     function );
181
182
0
    return( -1 );
183
0
  }
184
344
  if( data == NULL )
185
0
  {
186
0
    libcerror_error_set(
187
0
     error,
188
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
189
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
190
0
     "%s: invalid data.",
191
0
     function );
192
193
0
    return( -1 );
194
0
  }
195
344
  if( ( data_size < sizeof( modi_sparse_image_header_t ) )
196
344
   || ( data_size > (size_t) SSIZE_MAX ) )
197
0
  {
198
0
    libcerror_error_set(
199
0
     error,
200
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
201
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
202
0
     "%s: invalid data size value out of bounds.",
203
0
     function );
204
205
0
    return( -1 );
206
0
  }
207
#if defined( HAVE_DEBUG_OUTPUT )
208
  if( libcnotify_verbose != 0 )
209
  {
210
    libcnotify_printf(
211
     "%s: sparse image header data:\n",
212
     function );
213
    libcnotify_print_data(
214
     data,
215
     sizeof( modi_sparse_image_header_t ),
216
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
217
  }
218
#endif
219
344
  if( memory_compare(
220
344
       ( (modi_sparse_image_header_t *) data )->signature,
221
344
       modi_sparse_image_signature,
222
344
       4 ) != 0 )
223
165
  {
224
165
    return( 0 );
225
165
  }
226
179
  byte_stream_copy_to_uint32_big_endian(
227
179
   ( (modi_sparse_image_header_t *) data )->sectors_per_band,
228
179
   sparse_image_header->sectors_per_band );
229
230
179
  byte_stream_copy_to_uint32_big_endian(
231
179
   ( (modi_sparse_image_header_t *) data )->number_of_sectors,
232
179
   sparse_image_header->number_of_sectors );
233
234
#if defined( HAVE_DEBUG_OUTPUT )
235
  if( libcnotify_verbose != 0 )
236
  {
237
    libcnotify_printf(
238
     "%s: signature\t\t\t: %c%c%c%c\n",
239
     function,
240
     ( (modi_sparse_image_header_t *) data )->signature[ 0 ],
241
     ( (modi_sparse_image_header_t *) data )->signature[ 1 ],
242
     ( (modi_sparse_image_header_t *) data )->signature[ 2 ],
243
     ( (modi_sparse_image_header_t *) data )->signature[ 3 ] );
244
245
    byte_stream_copy_to_uint32_big_endian(
246
     ( (modi_sparse_image_header_t *) data )->unknown1,
247
     value_32bit );
248
    libcnotify_printf(
249
     "%s: unknown1\t\t\t\t: %" PRIu32 "\n",
250
     function,
251
     value_32bit );
252
253
    libcnotify_printf(
254
     "%s: sectors per band\t\t\t: %" PRIu32 "\n",
255
     function,
256
     sparse_image_header->sectors_per_band );
257
258
    byte_stream_copy_to_uint32_big_endian(
259
     ( (modi_sparse_image_header_t *) data )->unknown2,
260
     value_32bit );
261
    libcnotify_printf(
262
     "%s: unknown2\t\t\t\t: %" PRIu32 "\n",
263
     function,
264
     value_32bit );
265
266
    libcnotify_printf(
267
     "%s: number of sectors\t\t: %" PRIu32 "\n",
268
     function,
269
     sparse_image_header->number_of_sectors );
270
271
    libcnotify_printf(
272
     "%s: unknown3:\n",
273
     function );
274
    libcnotify_print_data(
275
     ( (modi_sparse_image_header_t *) data )->unknown3,
276
     12,
277
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
278
279
    byte_stream_copy_to_uint32_big_endian(
280
     ( (modi_sparse_image_header_t *) data )->unknown4,
281
     value_32bit );
282
    libcnotify_printf(
283
     "%s: unknown4\t\t\t\t: 0x%08" PRIx32 "\n",
284
     function,
285
     value_32bit );
286
287
    libcnotify_printf(
288
     "%s: unknown5:\n",
289
     function );
290
    libcnotify_print_data(
291
     ( (modi_sparse_image_header_t *) data )->unknown5,
292
     28,
293
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
294
  }
295
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
296
297
179
  data_offset = sizeof( modi_sparse_image_header_t );
298
299
179
  if( sparse_image_header->sectors_per_band == 0 )
300
1
  {
301
1
    libcerror_error_set(
302
1
     error,
303
1
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
304
1
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
305
1
     "%s: invalid sectors per band value out of bounds.",
306
1
     function );
307
308
1
    goto on_error;
309
1
  }
310
178
  sparse_image_header->number_of_bands = sparse_image_header->number_of_sectors / sparse_image_header->sectors_per_band;
311
312
178
  if( ( sparse_image_header->number_of_sectors % sparse_image_header->sectors_per_band ) != 0 )
313
128
  {
314
128
    sparse_image_header->number_of_bands += 1;
315
128
  }
316
178
  if( sparse_image_header->number_of_bands > 0 )
317
177
  {
318
177
    if( sparse_image_header->number_of_bands > (uint32_t) ( MEMORY_MAXIMUM_ALLOCATION_SIZE / sizeof( uint32_t ) ) )
319
32
    {
320
32
      libcerror_error_set(
321
32
       error,
322
32
       LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
323
32
       LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
324
32
       "%s: invalid number of bands value exceeds maximum.",
325
32
       function );
326
327
32
      goto on_error;
328
32
    }
329
145
    bands_table_data_size = sparse_image_header->number_of_bands * sizeof( uint32_t );
330
331
145
    if( bands_table_data_size > ( data_size - data_offset ) )
332
50
    {
333
50
      libcerror_error_set(
334
50
       error,
335
50
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
336
50
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
337
50
       "%s: invalid bands table data size value out of bounds.",
338
50
       function );
339
340
50
      goto on_error;
341
50
    }
342
#if defined( HAVE_DEBUG_OUTPUT )
343
    if( libcnotify_verbose != 0 )
344
    {
345
      libcnotify_printf(
346
       "%s: bands table data:\n",
347
       function );
348
      libcnotify_print_data(
349
       &( data[ data_offset ] ),
350
       bands_table_data_size,
351
       LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
352
    }
353
#endif
354
95
    sparse_image_header->band_references = (uint32_t *) memory_allocate(
355
95
                                                         bands_table_data_size );
356
357
95
    if( sparse_image_header->band_references == NULL )
358
0
    {
359
0
      libcerror_error_set(
360
0
       error,
361
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
362
0
       LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
363
0
       "%s: unable to create band references.",
364
0
       function );
365
366
0
      goto on_error;
367
0
    }
368
95
    if( memory_set(
369
95
         sparse_image_header->band_references,
370
95
         0xff,
371
95
         bands_table_data_size ) == NULL )
372
0
    {
373
0
      libcerror_error_set(
374
0
       error,
375
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
376
0
       LIBCERROR_MEMORY_ERROR_SET_FAILED,
377
0
       "%s: unable to clear band references.",
378
0
       function );
379
380
0
      goto on_error;
381
0
    }
382
95
    for( bands_table_index = 0;
383
3.89k
         bands_table_index < sparse_image_header->number_of_bands;
384
3.79k
         bands_table_index++ )
385
3.86k
    {
386
3.86k
      byte_stream_copy_to_uint32_big_endian(
387
3.86k
       &( data[ data_offset ] ),
388
3.86k
       bands_table_reference );
389
390
3.86k
      data_offset += 4;
391
392
#if defined( HAVE_DEBUG_OUTPUT )
393
      if( libcnotify_verbose != 0 )
394
      {
395
        libcnotify_printf(
396
         "%s: bands table reference: %03" PRIu32 "\t: 0x%08" PRIx32 " (%" PRIi32 ")\n",
397
         function,
398
         bands_table_index,
399
         bands_table_reference,
400
         (int32_t) bands_table_reference );
401
      }
402
#endif
403
3.86k
      if( bands_table_reference != 0 )
404
660
      {
405
660
        if( bands_table_reference > sparse_image_header->number_of_bands )
406
73
        {
407
73
          libcerror_error_set(
408
73
           error,
409
73
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
410
73
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
411
73
           "%s: invalid bands table reference value out of bounds.",
412
73
           function );
413
414
73
          goto on_error;
415
73
        }
416
587
        ( sparse_image_header->band_references )[ bands_table_reference - 1 ] = bands_table_index;
417
587
      }
418
3.86k
    }
419
#if defined( HAVE_DEBUG_OUTPUT )
420
    if( libcnotify_verbose != 0 )
421
    {
422
      libcnotify_printf(
423
       "\n" );
424
    }
425
#endif
426
95
  }
427
23
  data_offset += bands_table_data_size;
428
429
#if defined( HAVE_DEBUG_OUTPUT )
430
  if( ( libcnotify_verbose != 0 )
431
   && ( data_offset < data_size ) )
432
  {
433
    libcnotify_printf(
434
     "%s: trailing data:\n",
435
     function );
436
    libcnotify_print_data(
437
     &( data[ data_offset ] ),
438
     data_size - data_offset,
439
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
440
  }
441
#endif
442
23
  return( 1 );
443
444
156
on_error:
445
156
  if( sparse_image_header->band_references != NULL )
446
73
  {
447
73
    memory_free(
448
73
     sparse_image_header->band_references );
449
450
73
    sparse_image_header->band_references = 0;
451
73
  }
452
156
  return( -1 );
453
178
}
454
455
/* Reads a sparse image header
456
 * Returns 1 if successful, 0 if the signature does not match or -1 on error
457
 */
458
int libmodi_sparse_image_header_read_file_io_handle(
459
     libmodi_sparse_image_header_t *sparse_image_header,
460
     libbfio_handle_t *file_io_handle,
461
     off64_t offset,
462
     libcerror_error_t **error )
463
344
{
464
344
  uint8_t *sparse_image_header_data = NULL;
465
344
  static char *function             = "libmodi_sparse_image_header_read_file_io_handle";
466
344
  size_t read_size                  = 4096;
467
344
  ssize_t read_count                = 0;
468
344
  int result                        = 0;
469
470
344
  if( sparse_image_header == NULL )
471
0
  {
472
0
    libcerror_error_set(
473
0
     error,
474
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
475
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
476
0
     "%s: invalid sparse image header.",
477
0
     function );
478
479
0
    return( -1 );
480
0
  }
481
344
  sparse_image_header_data = (uint8_t *) memory_allocate(
482
344
                                          read_size );
483
484
344
  if( sparse_image_header_data == NULL )
485
0
  {
486
0
    libcerror_error_set(
487
0
     error,
488
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
489
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
490
0
     "%s: unable to create sparse image header data.",
491
0
     function );
492
493
0
    goto on_error;
494
0
  }
495
#if defined( HAVE_DEBUG_OUTPUT )
496
  if( libcnotify_verbose != 0 )
497
  {
498
    libcnotify_printf(
499
     "%s: reading sparse image header at offset: %" PRIi64 " (0x%08" PRIx64 ").\n",
500
     function,
501
     offset,
502
     offset );
503
  }
504
#endif
505
344
  read_count = libbfio_handle_read_buffer_at_offset(
506
344
                file_io_handle,
507
344
                sparse_image_header_data,
508
344
                read_size,
509
344
                offset,
510
344
                error );
511
512
344
  if( read_count != (ssize_t) read_size )
513
0
  {
514
0
    libcerror_error_set(
515
0
     error,
516
0
     LIBCERROR_ERROR_DOMAIN_IO,
517
0
     LIBCERROR_IO_ERROR_READ_FAILED,
518
0
     "%s: unable to read sparse image header data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
519
0
     function,
520
0
     offset,
521
0
     offset );
522
523
0
    goto on_error;
524
0
  }
525
344
  result = libmodi_sparse_image_header_read_data(
526
344
            sparse_image_header,
527
344
            sparse_image_header_data,
528
344
            read_size,
529
344
            error );
530
531
344
  if( result == -1 )
532
156
  {
533
156
    libcerror_error_set(
534
156
     error,
535
156
     LIBCERROR_ERROR_DOMAIN_IO,
536
156
     LIBCERROR_IO_ERROR_READ_FAILED,
537
156
     "%s: unable to read sparse image header.",
538
156
     function );
539
540
156
    goto on_error;
541
156
  }
542
188
  memory_free(
543
188
   sparse_image_header_data );
544
545
188
  sparse_image_header_data = NULL;
546
547
188
  return( result );
548
549
156
on_error:
550
156
  if( sparse_image_header_data != NULL )
551
156
  {
552
156
    memory_free(
553
156
     sparse_image_header_data );
554
156
  }
555
156
  return( -1 );
556
344
}
557