"Fossies" - the Fresh Open Source Software Archive 
Member "snort-2.9.17/src/file-process/file_capture.c" (16 Oct 2020, 18480 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "file_capture.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.9.16.1_vs_2.9.17.
1 /*
2 ** Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
3 ** Copyright (C) 2013-2013 Sourcefire, Inc.
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License Version 2 as
7 ** published by the Free Software Foundation. You may not use, modify or
8 ** distribute this program under any other version of the GNU General
9 ** Public License.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 **
20 ** Author(s): Hui Cao <hcao@sourcefire.com>
21 **
22 ** NOTES
23 ** 5.05.2013 - Initial Source Code. Hcao
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "sf_types.h"
31 #include "file_capture.h"
32 #include "file_mempool.h"
33 #include "util.h"
34 #include <sys/stat.h>
35 #include "sf_sechash.h"
36 #include "snort.h"
37 #include "stream_api.h"
38 #include "file_config.h"
39 #include "file_stats.h"
40 #include "file_service.h"
41
42 #include <unistd.h>
43 #include <string.h>
44 #include <fcntl.h>
45 #include <sys/types.h>
46
47 SafeMemPool *file_mempool = NULL;
48 File_Capture_Stats file_capture_stats;
49
50 /*
51 * Verify file capture information and file context information matched
52 * This is used for debug purpose
53 */
54
55 #ifdef DEBUG_MSGS
56 static void verify_file_capture_info(FileContext* context,
57 FileCaptureInfo *fileInfo)
58 {
59 /* file capture length should be one of two possible values */
60 if (context->processed_bytes)
61 {
62 if ((fileInfo->file_size != context->processed_bytes) &&
63 (fileInfo->file_size + context->current_data_len
64 != context->processed_bytes))
65 {
66 FILE_DEBUG("File capture size failed w.r.t processed size!");
67 }
68 }
69 else
70 {
71 if ((fileInfo->file_size != context->file_size) &&
72 (fileInfo->file_size + context->current_data_len
73 != context->file_size))
74 {
75 FILE_DEBUG("File capture size failed w.r.t final file size!");
76 }
77 }
78 }
79
80 static void verifiy_file_capture(FileContext* context,
81 FileCaptureInfo *fileInfo)
82 {
83 SHA256CONTEXT sha_ctx;
84 uint8_t *buff;
85 int size;
86 FileCaptureInfo *file_mem = fileInfo;
87 uint8_t sha256[SHA256_HASH_SIZE + 1];
88 int i;
89
90 memset(&sha_ctx, 0, sizeof(sha_ctx));
91
92 /*Calculator the SHA*/
93 SHA256INIT(&sha_ctx);
94
95 while (file_mem)
96 {
97 file_mem = file_capture_read(file_mem, &buff, &size);
98 SHA256UPDATE(&sha_ctx, buff, size);
99 }
100
101 SHA256FINAL(sha256, &sha_ctx);
102
103 for (i = 0; i < SHA256_HASH_SIZE; i++)
104 {
105 if (sha256[i] != context->sha256[i])
106 {
107 FILE_DEBUG("File capture buffer is wrong! SHA256 mismatch");
108 break;
109 }
110 }
111 }
112 #endif
113
114 /*
115 * Initialize the file memory pool
116 *
117 * Returns:
118 * void *: pointer to mempool
119 * NULL : fail to initialize file mempool
120 */
121 static void* _init_file_mempool(int64_t max_file_mem, int64_t block_size)
122 {
123 int max_files;
124 SafeMemPool *file_mempool;
125 int64_t max_file_mem_in_bytes;
126
127 /*Convert megabytes to bytes*/
128 max_file_mem_in_bytes = max_file_mem * 1024 * 1024;
129
130 if (block_size <= 0)
131 return NULL;
132
133 if (block_size & 7)
134 block_size += (8 - (block_size & 7));
135
136 max_files = max_file_mem_in_bytes / block_size ;
137
138 file_mempool = (SafeMemPool *)calloc(1, sizeof(SafeMemPool));
139
140 if ((!file_mempool)||
141 (safe_mempool_init(file_mempool, max_files, block_size) != 0))
142 {
143 FatalError( "File capture: Could not allocate file buffer mempool.\n");
144 }
145
146 return file_mempool;
147 }
148
149 /*
150 * Initialize the file memory pool
151 *
152 * Arguments:
153 * int64_t max_file_mem: memcap in megabytes
154 * int64_t block_size: file block size (metadata size excluded)
155 *
156 * Returns: NONE
157 */
158 void file_capture_init_mempool(int64_t max_file_mem, int64_t block_size)
159 {
160 int64_t metadata_size = sizeof (FileCaptureInfo);
161
162 if(!file_mempool)
163 file_mempool = _init_file_mempool(max_file_mem,
164 block_size + metadata_size);
165
166 }
167
168 /* Free file buffer list*/
169 static inline void _free_file_buffer(FileCaptureInfo *fileInfo)
170 {
171 file_capture_stats.files_freed_total++;
172
173 while (fileInfo)
174 {
175 if (safe_mempool_free(file_mempool, fileInfo) != SAFE_MEM_SUCCESS)
176 file_capture_stats.file_buffers_free_errors++;
177 fileInfo = fileInfo->next;
178 file_capture_stats.file_buffers_freed_total++;
179 }
180 }
181
182 /* Release file buffer list*/
183 static inline void _release_file_buffer(FileCaptureInfo *fileInfo)
184 {
185 file_capture_stats.files_released_total++;
186
187 while (fileInfo)
188 {
189 if (safe_mempool_release(file_mempool, fileInfo) != SAFE_MEM_SUCCESS)
190 file_capture_stats.file_buffers_release_errors++;
191 fileInfo = fileInfo->next;
192 file_capture_stats.file_buffers_released_total++;
193 }
194 }
195
196 /*
197 * Stop file capture, memory resource will be released if not reserved
198 *
199 * Returns: NONE
200 */
201 void file_capture_stop( FileContext* context)
202 {
203 FileCaptureInfo *fileInfo = context->file_capture;
204
205 if (fileInfo)
206 {
207 /*free mempool*/
208 if(!fileInfo->reserved)
209 {
210 _free_file_buffer(fileInfo);
211 }
212 context->file_capture = NULL;
213 }
214 context->file_capture_enabled = false;
215 }
216
217 /*
218 * Create file buffer in file mempool
219 *
220 * Args:
221 * SafeMemPool *file_mempool: file mempool
222 * FileContext* context: file context
223 *
224 * Returns:
225 * FileCaptureInfo *: memory block that starts with file capture information
226 */
227 static inline FileCaptureInfo * _create_file_buffer(SafeMemPool *file_mempool)
228 {
229
230 FileCaptureInfo *fileInfo;
231 uint64_t num_files_queued;
232
233 fileInfo = (FileCaptureInfo*)safe_mempool_alloc(file_mempool);
234
235 if(fileInfo == NULL)
236 {
237 FILE_DEBUG("Failed to get file capture memory!");
238 file_capture_stats.file_memcap_failures_total++;
239 return NULL;
240 }
241
242 file_capture_stats.file_buffers_allocated_total++;
243
244 fileInfo->length = 0;
245 fileInfo->reserved = false;
246 fileInfo->next = NULL; /*Only one block initially*/
247 fileInfo->last = fileInfo;
248 fileInfo->file_size = 0;
249
250 num_files_queued = safe_mempool_allocated(file_mempool);
251 if (file_capture_stats.file_buffers_used_max < num_files_queued)
252 file_capture_stats.file_buffers_used_max = num_files_queued;
253
254 return fileInfo;
255 }
256
257 /*
258 * Save file to the buffer
259 * If file needs to be extracted, buffer will be reserved
260 * If file buffer isn't sufficient, need to add another buffer.
261 *
262 * Returns:
263 * 0: successful or file capture is disabled
264 * 1: fail to capture the file
265 */
266 static inline int _save_to_file_buffer(SafeMemPool *file_mempool,
267 FileContext* context, uint8_t* file_data, int data_size,
268 int64_t max_size)
269 {
270 FileCaptureInfo *fileInfo = (FileCaptureInfo *) context->file_capture;
271 FileCaptureInfo *lastBlock = fileInfo->last;
272 uint64_t available_bytes;
273 FileConfig *file_config = (FileConfig *)(snort_conf->file_config);
274
275 DEBUG_WRAP(verify_file_capture_info(context, fileInfo););
276
277 if ( data_size + (signed)fileInfo->file_size > max_size)
278 {
279 FILE_DEBUG("Exceeding max file capture size!");
280 file_capture_stats.file_size_exceeded++;
281 context->file_state.capture_state = FILE_CAPTURE_MAX;
282 return -1;
283 }
284
285 /* Check whether current file block can hold file data*/
286 available_bytes = file_config->file_capture_block_size - lastBlock->length;
287 if ( available_bytes > file_config->file_capture_block_size)
288 {
289 context->file_state.capture_state = FILE_CAPTURE_MEMCAP;
290 return -1;
291 }
292
293 if ( data_size > available_bytes)
294 {
295 FileCaptureInfo *new_block;
296 uint8_t* file_current = file_data;
297 uint8_t* file_end = file_data + data_size;
298
299 /*can't hold all, use current block first*/
300 memcpy((uint8_t *)lastBlock + lastBlock->length + sizeof (*lastBlock),
301 file_current, available_bytes );
302
303 lastBlock->length = file_config->file_capture_block_size;
304 file_current += available_bytes;
305
306 /* We can support any file capture block size */
307 while (1)
308 {
309 /*get another block*/
310 new_block = (FileCaptureInfo *)_create_file_buffer(file_mempool);
311
312 if(new_block == NULL)
313 {
314 FILE_ERROR("Failed to save in file buffer: FILE_CAPTURE_MEMCAP");
315 context->file_state.capture_state = FILE_CAPTURE_MEMCAP;
316 return -1;
317 }
318
319 fileInfo->last->next = new_block;
320 fileInfo->last = new_block;
321
322 /*Save data to the new block*/
323 if (file_current + file_config->file_capture_block_size < file_end)
324 {
325 memcpy((uint8_t *)fileInfo->last + sizeof(*new_block),
326 file_current, file_config->file_capture_block_size);
327 new_block->length = file_config->file_capture_block_size;
328 file_current += file_config->file_capture_block_size;
329 }
330 else
331 {
332 memcpy((uint8_t *)fileInfo->last + sizeof(*new_block),
333 file_current, file_end - file_current);
334
335 new_block->length = file_end - file_current;
336 break;
337 }
338 }
339 }
340 else
341 {
342 memcpy((uint8_t *)lastBlock + lastBlock->length + sizeof(*lastBlock),
343 file_data, data_size);
344
345 lastBlock->length += data_size;
346 }
347
348 fileInfo->file_size += data_size;
349
350 DEBUG_WRAP(verify_file_capture_info(context, fileInfo);)
351 return 0;
352 }
353
354 /*
355 * Save files to the local buffer first for files transferred
356 * by multiple reassembled packets. For files within a packet,
357 * simply using the packet buffer.
358 * If file needs to be extracted, buffer will be reserved
359 *
360 * Arguments:
361 * FileContext* context: current file context
362 * uint8_t *file_data: current file data
363 * int data_size: current file data size
364 * FilePosition position: position of file data
365 * Returns:
366 * 0: successful
367 * 1: fail to capture the file or file capture is disabled
368 */
369 int file_capture_process( FileContext* context, uint8_t* file_data,
370 int data_size, FilePosition position )
371 {
372
373 FileCaptureInfo *fileInfo = (FileCaptureInfo *) context->file_capture;
374 FileConfig *file_config = (FileConfig *)(snort_conf->file_config);
375
376 context->current_data = file_data;
377 context->current_data_len = data_size;
378 FILE_DEBUG("Processing capture: context: %p, data_size: %d, position: %d", context, data_size, position);
379
380 switch (position)
381 {
382 case SNORT_FILE_FULL:
383 file_capture_stats.file_within_packet++;
384 break;
385 case SNORT_FILE_END:
386 break;
387 case SNORT_FILE_START:
388 case SNORT_FILE_MIDDLE:
389 if(FILE_SIG_FLUSH == context->file_state.sig_state){
390 break;
391 }
392 default:
393
394 /* For File position is either SNORT_FILE_START
395 * or SNORT_FILE_MIDDLE, the file is larger than one packet,
396 * we need to store them into buffer.
397 */
398
399 if(!context->file_capture)
400 {
401 fileInfo = _create_file_buffer(file_mempool);
402
403 if (!fileInfo)
404 {
405 FILE_ERROR("Processing file capture: Can't get file capture memory, FILE_CAPTURE_MEMCAP");
406 context->file_state.capture_state = FILE_CAPTURE_MEMCAP;
407 return -1;
408 }
409
410 file_capture_stats.files_buffered_total++;
411
412 context->file_capture = fileInfo;
413 }
414
415 if (!fileInfo)
416 {
417 FILE_ERROR("Processing file capture: File info not available");
418 return -1;
419 }
420
421 if (_save_to_file_buffer(file_mempool, context, file_data, data_size,
422 file_config->file_capture_max_size))
423 {
424 FILE_ERROR("Processing file capture: Can't save to file buffer!");
425 return -1;
426 }
427 }
428
429 return 0;
430 }
431
432 /*Helper function for error*/
433 static inline FileCaptureState ERROR_capture(FileCaptureState state)
434 {
435 file_capture_stats.file_reserve_failures++;
436 return state;
437 }
438
439 /*
440 * Preserve the file in memory until it is released
441 *
442 * Arguments:
443 * void *ssnptr: session pointer
444 * void **file_mem: the pointer to store the memory block
445 * that stores file and its metadata.
446 * It will set NULL if no memory or fail to store
447 *
448 * Returns:
449 * FileCaptureState
450 *
451 */
452 FileCaptureState file_capture_reserve(void *ssnptr, FileCaptureInfo **file_mem)
453 {
454 FileContext* context;
455 FileCaptureInfo *fileInfo;
456 uint64_t fileSize;
457 FileConfig *file_config = (FileConfig *)(snort_conf->file_config);
458
459 if (!ssnptr||!file_config||!file_mem)
460 {
461 FILE_ERROR("Capture failed: No session/memory/config");
462 return ERROR_capture(FILE_CAPTURE_FAIL);
463 }
464
465 context = get_current_file_context(ssnptr);
466
467 if (!context || !context->file_capture_enabled)
468 {
469 FILE_ERROR("Capture failed: Not enabled");
470 return ERROR_capture(FILE_CAPTURE_FAIL);
471 }
472
473 if (context->file_state.capture_state != FILE_CAPTURE_SUCCESS)
474 {
475 FILE_ERROR("Capture failed: %d",context->file_state.capture_state);
476 return ERROR_capture(context->file_state.capture_state);
477 }
478
479 fileInfo = (FileCaptureInfo *)(context->file_capture);
480
481 /*
482 * Note: file size is updated at this point
483 */
484 fileSize = context->file_size;
485
486 if ((!context->partial_file) && (fileSize < (unsigned) file_config->file_capture_min_size))
487 {
488 file_capture_stats.file_size_min++;
489 FILE_ERROR("Capture failed: FILE_CAPTURE_MIN, size: %d",fileSize);
490 return ERROR_capture(FILE_CAPTURE_MIN);
491 }
492
493 if ( fileSize > (unsigned) file_config->file_capture_max_size)
494 {
495 file_capture_stats.file_size_max++;
496 FILE_ERROR("Capture failed: FILE_CAPTURE_MAX, size: %d",fileSize);
497 return ERROR_capture(FILE_CAPTURE_MAX);
498 }
499
500 /* Create a file buffer if it is not done yet,
501 * This is the case for small file
502 */
503 if(!fileInfo && context->file_capture_enabled)
504 {
505
506 fileInfo = _create_file_buffer(file_mempool);
507
508 if (!fileInfo)
509 {
510 file_capture_stats.file_memcap_failures_reserve++;
511 FILE_ERROR("Capture failed: FILE_CAPTURE_MEMCAP");
512 return ERROR_capture(FILE_CAPTURE_MEMCAP);
513 }
514
515 file_capture_stats.files_buffered_total++;
516 context->file_capture = fileInfo;
517
518 DEBUG_WRAP(verify_file_capture_info(context, fileInfo););
519 }
520
521 if (!fileInfo)
522 {
523 FILE_ERROR("Capture failed: FILE_CAPTURE_MEMCAP");
524 return ERROR_capture(FILE_CAPTURE_MEMCAP);
525 }
526
527 DEBUG_WRAP(verify_file_capture_info(context, fileInfo););
528
529 /*Copy the last piece of file to file buffer*/
530 if (_save_to_file_buffer(file_mempool, context, context->current_data,
531 context->current_data_len, file_config->file_capture_max_size) )
532 {
533 FILE_ERROR("Capture failed: %d",context->file_state.capture_state);
534 return ERROR_capture(context->file_state.capture_state);
535 }
536
537 file_capture_stats.files_captured_total++;
538
539 *file_mem = fileInfo;
540
541 fileInfo->reserved = true;
542
543 /* Clear file capture information on file context
544 * Without this, the next file within the same session
545 * might use this information to change shared memory buffer
546 * that might be released and then used by other sessions
547 */
548 if(context->file_state.sig_state != FILE_SIG_FLUSH)
549 {
550 context->file_capture = NULL;
551 context->file_capture_enabled = false;
552 }
553 DEBUG_WRAP(verifiy_file_capture(context, fileInfo););
554 FILE_INFO("Capture successful");
555
556 return FILE_CAPTURE_SUCCESS;
557 }
558
559 /*
560 * Get the file that is reserved in memory
561 *
562 * Arguments:
563 * void *: the memory block that stores file and its metadata
564 * uint8_t **buff: address to store buffer address
565 * int *size: address to store size of file
566 *
567 * Returns:
568 * the next memory block that stores file and its metadata
569 * NULL: no more file data or fail to get file
570 */
571 void* file_capture_read(FileCaptureInfo *fileInfo, uint8_t **buff, int *size)
572 {
573 if (!fileInfo || !buff || !size)
574 {
575 FILE_ERROR("Failed to read capture");
576 return NULL;
577 }
578
579 *buff = (uint8_t *)fileInfo + sizeof(*fileInfo);
580 *size = fileInfo->length;
581
582 return (fileInfo->next);
583 }
584
585 /*
586 * Get the file size captured in the file buffer
587 *
588 * Arguments:
589 * void *file_mem: the first memory block of file buffer
590 *
591 * Returns:
592 * the size of file
593 * 0: not the first file block or fail to get file
594 */
595 size_t file_capture_size(FileCaptureInfo *fileInfo)
596 {
597 if (!fileInfo)
598 return 0;
599
600 return fileInfo->file_size;
601 }
602
603 /*
604 * Release the file that is reserved in memory, this function might be
605 * called in a different thread.
606 *
607 * Arguments:
608 * void *data: the memory block that stores file and its metadata
609 */
610 void file_capture_release(FileCaptureInfo *fileInfo)
611 {
612 if (!fileInfo)
613 return;
614
615 fileInfo->reserved = false;
616
617 _release_file_buffer(fileInfo);
618
619 }
620
621 /*Log file capture mempool usage*/
622 void file_capture_mem_usage(void)
623 {
624 if (file_mempool)
625 {
626 LogMessage("Maximum buffers can allocate: "FMTu64("-10")" \n",
627 file_mempool->total);
628 LogMessage("Number of buffers in use: "FMTu64("-10")" \n",
629 safe_mempool_allocated(file_mempool));
630 LogMessage("Number of buffers in free list: "FMTu64("-10")" \n",
631 safe_mempool_freed(file_mempool));
632 LogMessage("Number of buffers in release list: "FMTu64("-10")" \n",
633 safe_mempool_released(file_mempool));
634 }
635
636 }
637
638 /*
639 * Release all file capture memory etc,
640 * this must be called when snort exits
641 */
642 void file_caputure_close(void)
643 {
644
645 if (safe_mempool_destroy(file_mempool) == 0)
646 {
647 free(file_mempool);
648 file_mempool = NULL;
649 }
650
651 }