"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 }