1 /*
2  * Grain data functions
3  *
4  * Copyright (C) 2009-2021, 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 "libvmdk_compression.h"
28 #include "libvmdk_definitions.h"
29 #include "libvmdk_grain_data.h"
30 #include "libvmdk_handle.h"
31 #include "libvmdk_io_handle.h"
32 #include "libvmdk_libcerror.h"
33 #include "libvmdk_libcnotify.h"
34 #include "libvmdk_libfdata.h"
35 #include "libvmdk_unused.h"
36 
37 /* Creates grain data
38  * Make sure the value grain_data is referencing, is set to NULL
39  * Returns 1 if successful or -1 on error
40  */
libvmdk_grain_data_initialize(libvmdk_grain_data_t ** grain_data,size_t data_size,libcerror_error_t ** error)41 int libvmdk_grain_data_initialize(
42      libvmdk_grain_data_t **grain_data,
43      size_t data_size,
44      libcerror_error_t **error )
45 {
46 	static char *function = "libvmdk_grain_data_initialize";
47 
48 	if( grain_data == NULL )
49 	{
50 		libcerror_error_set(
51 		 error,
52 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54 		 "%s: invalid grain data.",
55 		 function );
56 
57 		return( -1 );
58 	}
59 	if( *grain_data != NULL )
60 	{
61 		libcerror_error_set(
62 		 error,
63 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
64 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65 		 "%s: invalid grain data value already set.",
66 		 function );
67 
68 		return( -1 );
69 	}
70 	if( ( data_size == 0 )
71 	 || ( data_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
72 	{
73 		libcerror_error_set(
74 		 error,
75 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
76 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
77 		 "%s: invalid data size value out of bounds.",
78 		 function );
79 
80 		return( -1 );
81 	}
82 	*grain_data = memory_allocate_structure(
83 	               libvmdk_grain_data_t );
84 
85 	if( *grain_data == NULL )
86 	{
87 		libcerror_error_set(
88 		 error,
89 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
90 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
91 		 "%s: unable to create grain data.",
92 		 function );
93 
94 		goto on_error;
95 	}
96 	if( memory_set(
97 	     *grain_data,
98 	     0,
99 	     sizeof( libvmdk_grain_data_t ) ) == NULL )
100 	{
101 		libcerror_error_set(
102 		 error,
103 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
104 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
105 		 "%s: unable to clear grain data.",
106 		 function );
107 
108 		goto on_error;
109 	}
110 	( *grain_data )->data = (uint8_t *) memory_allocate(
111 	                                     sizeof( uint8_t ) * data_size );
112 
113 	if( ( *grain_data )->data == NULL )
114 	{
115 		libcerror_error_set(
116 		 error,
117 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
118 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
119 		 "%s: unable to create data.",
120 		 function );
121 
122 		goto on_error;
123 	}
124 	( *grain_data )->data_size = data_size;
125 
126 	return( 1 );
127 
128 on_error:
129 	if( *grain_data != NULL )
130 	{
131 		memory_free(
132 		 *grain_data );
133 
134 		*grain_data = NULL;
135 	}
136 	return( -1 );
137 }
138 
139 /* Frees grain data
140  * Returns 1 if successful or -1 on error
141  */
libvmdk_grain_data_free(libvmdk_grain_data_t ** grain_data,libcerror_error_t ** error)142 int libvmdk_grain_data_free(
143      libvmdk_grain_data_t **grain_data,
144      libcerror_error_t **error )
145 {
146 	static char *function = "libvmdk_grain_data_free";
147 
148 	if( grain_data == NULL )
149 	{
150 		libcerror_error_set(
151 		 error,
152 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
153 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
154 		 "%s: invalid grain data.",
155 		 function );
156 
157 		return( -1 );
158 	}
159 	if( *grain_data != NULL )
160 	{
161 		if( ( *grain_data )->data != NULL )
162 		{
163 			memory_free(
164 			 ( *grain_data )->data );
165 		}
166 		memory_free(
167 		 *grain_data );
168 
169 		*grain_data = NULL;
170 	}
171 	return( 1 );
172 }
173 
174 /* Reads a compressed grain data header
175  * The number of bytes read or -1 on error
176  */
libvmdk_grain_data_read_compressed_header(libvmdk_grain_data_t * grain_data,libvmdk_io_handle_t * io_handle,libbfio_pool_t * file_io_pool,int file_io_pool_entry,libcerror_error_t ** error)177 ssize_t libvmdk_grain_data_read_compressed_header(
178          libvmdk_grain_data_t *grain_data,
179          libvmdk_io_handle_t *io_handle,
180          libbfio_pool_t *file_io_pool,
181          int file_io_pool_entry,
182          libcerror_error_t **error )
183 {
184 	uint8_t compressed_data_header[ 12 ];
185 
186 	static char *function = "libvmdk_grain_data_read_compressed_header";
187 	ssize_t read_count    = 0;
188 
189 	if( grain_data == NULL )
190 	{
191 		libcerror_error_set(
192 		 error,
193 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
195 		 "%s: invalid grain data.",
196 		 function );
197 
198 		return( -1 );
199 	}
200 	if( io_handle == NULL )
201 	{
202 		libcerror_error_set(
203 		 error,
204 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
205 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
206 		 "%s: invalid IO handle.",
207 		 function );
208 
209 		return( -1 );
210 	}
211 	read_count = libbfio_pool_read_buffer(
212 		      file_io_pool,
213 		      file_io_pool_entry,
214 		      compressed_data_header,
215 		      12,
216 		      error );
217 
218 	if( read_count != (ssize_t) 12 )
219 	{
220 		libcerror_error_set(
221 		 error,
222 		 LIBCERROR_ERROR_DOMAIN_IO,
223 		 LIBCERROR_IO_ERROR_READ_FAILED,
224 		 "%s: unable to read compressed grain data header.",
225 		 function );
226 
227 		return( -1 );
228 	}
229 #if defined( HAVE_DEBUG_OUTPUT )
230 	if( libcnotify_verbose != 0 )
231 	{
232 		libcnotify_printf(
233 		 "%s: compressed grain data header:\n",
234 		 function );
235 		libcnotify_print_data(
236 		 compressed_data_header,
237 		 12,
238 		 0 );
239 	}
240 #endif
241 	byte_stream_copy_to_uint64_little_endian(
242 	 compressed_data_header,
243 	 grain_data->uncompressed_data_offset );
244 
245 	byte_stream_copy_to_uint32_little_endian(
246 	 &( compressed_data_header[ 8 ] ),
247 	 grain_data->compressed_data_size );
248 
249 #if defined( HAVE_DEBUG_OUTPUT )
250 	if( libcnotify_verbose != 0 )
251 	{
252 		libcnotify_printf(
253 		 "%s: uncompressed data offset\t: %" PRIu64 " grains (0x%08" PRIx64 ")\n",
254 		 function,
255 		 grain_data->uncompressed_data_offset,
256 		 grain_data->uncompressed_data_offset * io_handle->grain_size );
257 
258 		libcnotify_printf(
259 		 "%s: compressed data size\t\t: %" PRIu32 "\n",
260 		 function,
261 		 grain_data->compressed_data_size );
262 
263 		libcnotify_printf(
264 		 "\n" );
265 	}
266 #endif
267 	grain_data->uncompressed_data_offset *= io_handle->grain_size;
268 
269 	return( read_count );
270 }
271 
272 /* Reads a grain
273  * Callback function for the grains list
274  * Returns 1 if successful or -1 on error
275  */
libvmdk_grain_data_read_element_data(libvmdk_io_handle_t * io_handle,libbfio_pool_t * file_io_pool,libfdata_list_element_t * element,libfdata_cache_t * cache,int file_io_pool_entry,off64_t grain_data_offset,size64_t grain_data_size,uint32_t grain_data_flags,uint8_t read_flags LIBVMDK_ATTRIBUTE_UNUSED,libcerror_error_t ** error)276 int libvmdk_grain_data_read_element_data(
277      libvmdk_io_handle_t *io_handle,
278      libbfio_pool_t *file_io_pool,
279      libfdata_list_element_t *element,
280      libfdata_cache_t *cache,
281      int file_io_pool_entry,
282      off64_t grain_data_offset,
283      size64_t grain_data_size,
284      uint32_t grain_data_flags,
285      uint8_t read_flags LIBVMDK_ATTRIBUTE_UNUSED,
286      libcerror_error_t **error )
287 {
288 	libvmdk_grain_data_t *grain_data = NULL;
289 	uint8_t *compressed_data         = NULL;
290 	static char *function            = "libvmdk_grain_data_read_element_data";
291 	ssize_t read_count               = 0;
292 
293 	LIBVMDK_UNREFERENCED_PARAMETER( read_flags )
294 
295 	if( io_handle == NULL )
296 	{
297 		libcerror_error_set(
298 		 error,
299 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
300 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
301 		 "%s: invalid IO handle.",
302 		 function );
303 
304 		return( -1 );
305 	}
306 	if( ( grain_data_size == (size64_t) 0 )
307 	 || ( grain_data_size > (size64_t) SSIZE_MAX ) )
308 	{
309 		libcerror_error_set(
310 		 error,
311 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
312 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
313 		 "%s: invalid grain data size value out of bounds.",
314 		 function );
315 
316 		return( -1 );
317 	}
318 	if( ( grain_data_flags & LIBVMDK_RANGE_FLAG_IS_SPARSE ) != 0 )
319 	{
320 		libcerror_error_set(
321 		 error,
322 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
323 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
324 		 "%s: sparse grain not supported.",
325 		 function );
326 
327 		return( -1 );
328 	}
329 	if( libbfio_pool_seek_offset(
330 	     file_io_pool,
331 	     file_io_pool_entry,
332 	     grain_data_offset,
333 	     SEEK_SET,
334 	     error ) == -1 )
335 	{
336 		libcerror_error_set(
337 		 error,
338 		 LIBCERROR_ERROR_DOMAIN_IO,
339 		 LIBCERROR_IO_ERROR_SEEK_FAILED,
340 		 "%s: unable to seek grain offset: %" PRIi64 " in file IO pool entry: %d.",
341 		 function,
342 		 grain_data_offset,
343 		 file_io_pool_entry );
344 
345 		goto on_error;
346 	}
347 	if( ( grain_data_flags & LIBVMDK_RANGE_FLAG_IS_COMPRESSED ) != 0 )
348 	{
349 		if( io_handle->grain_size > (size64_t) SSIZE_MAX )
350 		{
351 			libcerror_error_set(
352 			 error,
353 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
354 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
355 			 "%s: invalid IO handle - grain size value exceeds maximum.",
356 			 function );
357 
358 			goto on_error;
359 		}
360 		if( libvmdk_grain_data_initialize(
361 		     &grain_data,
362 		     (size_t) io_handle->grain_size,
363 		     error ) != 1 )
364 		{
365 			libcerror_error_set(
366 			 error,
367 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
368 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
369 			 "%s: unable to create grain data.",
370 			 function );
371 
372 			goto on_error;
373 		}
374 		read_count = libvmdk_grain_data_read_compressed_header(
375 		              grain_data,
376 		              io_handle,
377 		              file_io_pool,
378 		              file_io_pool_entry,
379 		              error );
380 
381 		if( read_count == -1 )
382 		{
383 			libcerror_error_set(
384 			 error,
385 			 LIBCERROR_ERROR_DOMAIN_IO,
386 			 LIBCERROR_IO_ERROR_READ_FAILED,
387 			 "%s: unable to read compressed grain data header.",
388 			 function );
389 
390 			goto on_error;
391 		}
392 		if( ( grain_data->compressed_data_size == 0 )
393 		 || ( grain_data->compressed_data_size > (uint32_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
394 		{
395 			libcerror_error_set(
396 			 error,
397 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
398 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
399 			 "%s: invalid grain data - compressed data size value out of bounds.",
400 			 function );
401 
402 			goto on_error;
403 		}
404 		compressed_data = (uint8_t *) memory_allocate(
405 		                               sizeof( uint8_t ) * (size_t) grain_data->compressed_data_size );
406 
407 		if( compressed_data == NULL )
408 		{
409 			libcerror_error_set(
410 			 error,
411 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
412 			 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
413 			 "%s: unable to create compressed data.",
414 			 function );
415 
416 			goto on_error;
417 		}
418 		read_count = libbfio_pool_read_buffer(
419 			      file_io_pool,
420 			      file_io_pool_entry,
421 			      compressed_data,
422 			      (size_t) grain_data->compressed_data_size,
423 			      error );
424 
425 		if( read_count != (ssize_t) grain_data->compressed_data_size )
426 		{
427 			libcerror_error_set(
428 			 error,
429 			 LIBCERROR_ERROR_DOMAIN_IO,
430 			 LIBCERROR_IO_ERROR_READ_FAILED,
431 			 "%s: unable to read compressed grain data.",
432 			 function );
433 
434 			goto on_error;
435 		}
436 		if( libvmdk_decompress_data(
437 		     compressed_data,
438 		     (size_t) grain_data->compressed_data_size,
439 		     LIBVMDK_COMPRESSION_METHOD_DEFLATE,
440 		     grain_data->data,
441 		     &( grain_data->data_size ),
442 		     error ) != 1 )
443 		{
444 			libcerror_error_set(
445 			 error,
446 			 LIBCERROR_ERROR_DOMAIN_COMPRESSION,
447 			 LIBCERROR_COMPRESSION_ERROR_DECOMPRESS_FAILED,
448 			 "%s: unable to decompress grain data.",
449 			 function );
450 
451 			goto on_error;
452 		}
453 		memory_free(
454 		 compressed_data );
455 
456 		compressed_data = NULL;
457 	}
458 	else
459 	{
460 		if( libvmdk_grain_data_initialize(
461 		     &grain_data,
462 		     (size_t) grain_data_size,
463 		     error ) != 1 )
464 		{
465 			libcerror_error_set(
466 			 error,
467 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
468 			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
469 			 "%s: unable to create grain data.",
470 			 function );
471 
472 			goto on_error;
473 		}
474 		if( grain_data == NULL )
475 		{
476 			libcerror_error_set(
477 			 error,
478 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
479 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
480 			 "%s: missing grain data.",
481 			 function );
482 
483 			goto on_error;
484 		}
485 		read_count = libbfio_pool_read_buffer(
486 			      file_io_pool,
487 			      file_io_pool_entry,
488 			      grain_data->data,
489 			      (size_t) grain_data_size,
490 			      error );
491 
492 		if( read_count != (ssize_t) grain_data_size )
493 		{
494 			libcerror_error_set(
495 			 error,
496 			 LIBCERROR_ERROR_DOMAIN_IO,
497 			 LIBCERROR_IO_ERROR_READ_FAILED,
498 			 "%s: unable to read grain data.",
499 			 function );
500 
501 			goto on_error;
502 		}
503 	}
504 	if( libfdata_list_element_set_element_value(
505 	     element,
506 	     (intptr_t *) file_io_pool,
507 	     cache,
508 	     (intptr_t *) grain_data,
509 	     (int (*)(intptr_t **, libcerror_error_t **)) &libvmdk_grain_data_free,
510 	     LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
511 	     error ) != 1 )
512 	{
513 		libcerror_error_set(
514 		 error,
515 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
516 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
517 		 "%s: unable to set grain data as element value.",
518 		 function );
519 
520 		goto on_error;
521 	}
522 	return( 1 );
523 
524 on_error:
525 	if( compressed_data != NULL )
526 	{
527 		memory_free(
528 		 compressed_data );
529 	}
530 	if( grain_data != NULL )
531 	{
532 		libvmdk_grain_data_free(
533 		 &grain_data,
534 		 NULL );
535 	}
536 	return( -1 );
537 }
538 
539