2018-09-21 16:49:38 -04:00
/*
* Byte comparison matcher support functions
*
2021-03-19 15:12:26 -07:00
* Copyright ( C ) 2018 - 2021 Cisco Systems , Inc . and / or its affiliates . All rights reserved .
2018-09-21 16:49:38 -04:00
*
* Authors : Mickey Sola
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
*/
# if HAVE_CONFIG_H
# include "clamav-config.h"
# endif
2018-09-26 16:40:28 -04:00
# include <errno.h>
2018-09-21 16:49:38 -04:00
# include "clamav.h"
# include "others.h"
# include "matcher.h"
# include "matcher-ac.h"
# include "matcher-byte-comp.h"
# include "mpool.h"
# include "readdb.h"
# include "str.h"
/* DEBUGGING */
2018-10-25 14:30:07 -04:00
//#define MATCHER_BCOMP_DEBUG
2018-09-21 16:49:38 -04:00
# ifdef MATCHER_BCOMP_DEBUG
2018-12-03 12:40:13 -05:00
# define bcm_dbgmsg(...) cli_dbgmsg(__VA_ARGS__)
2018-09-21 16:49:38 -04:00
# else
2018-12-03 12:40:13 -05:00
# define bcm_dbgmsg(...)
2018-09-21 16:49:38 -04:00
# endif
# undef MATCHER_BCOMP_DEBUG
/* BCOMP MATCHER FUNCTIONS */
/**
* @ brief function to add the byte compare subsig into the matcher root struct
*
* @ param root the matcher root struct in question , houses all relevant lsig and subsig info
* @ param virname virusname as given by the signature
* @ param hexsig the raw sub signature buffer itself which we will be checking / parsing
* @ param lsigid the numeric internal reference number which can be used to access this lsig in the root struct
* @ param options additional options for pattern matching , stored as a bitmask
*
*/
2018-12-03 12:40:13 -05:00
cl_error_t cli_bcomp_addpatt ( struct cli_matcher * root , const char * virname , const char * hexsig , const uint32_t * lsigid , unsigned int options )
{
2018-09-21 16:49:38 -04:00
2018-12-03 12:40:13 -05:00
size_t len = 0 ;
uint32_t i = 0 ;
2018-09-21 16:49:38 -04:00
const char * buf_start = NULL ;
2018-12-03 12:40:13 -05:00
const char * buf_end = NULL ;
char * buf = NULL ;
2018-09-25 17:44:19 -04:00
const char * tokens [ 4 ] ;
2018-12-03 12:40:13 -05:00
size_t toks = 0 ;
2018-09-21 16:49:38 -04:00
int16_t ref_subsigid = - 1 ;
int64_t offset_param = 0 ;
2018-12-03 12:40:13 -05:00
int64_t ret = CL_SUCCESS ;
size_t byte_length = 0 ;
int64_t comp_val = 0 ;
char * comp_buf = NULL ;
char * comp_start = NULL ;
char * comp_end = NULL ;
2018-09-21 16:49:38 -04:00
2018-09-25 17:44:19 -04:00
if ( ! hexsig | | ! ( * hexsig ) | | ! root | | ! virname ) {
return CL_ENULLARG ;
}
2018-09-21 16:49:38 -04:00
/* we'll be using these to help the root matcher struct keep track of each loaded byte compare pattern */
2018-12-03 12:40:13 -05:00
struct cli_bcomp_meta * * newmetatable ;
2018-09-21 16:49:38 -04:00
uint32_t bcomp_count = 0 ;
/* zero out our byte compare data struct and tie it to the root struct's mempool instance */
struct cli_bcomp_meta * bcomp ;
2019-05-03 18:16:03 -04:00
bcomp = ( struct cli_bcomp_meta * ) MPOOL_CALLOC ( root - > mempool , 1 , sizeof ( * bcomp ) ) ;
2018-09-21 16:49:38 -04:00
if ( ! bcomp ) {
cli_errmsg ( " cli_bcomp_addpatt: Unable to allocate memory for new byte compare meta \n " ) ;
return CL_EMEM ;
}
/* allocate virname space with the root structure's mempool instance */
2019-05-03 18:16:03 -04:00
bcomp - > virname = ( char * ) CLI_MPOOL_VIRNAME ( root - > mempool , virname , options & CL_DB_OFFICIAL ) ;
2018-12-03 12:40:13 -05:00
if ( ! bcomp - > virname ) {
2018-09-21 16:49:38 -04:00
cli_errmsg ( " cli_bcomp_addpatt: Unable to allocate memory for virname or NULL virname \n " ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMEM ;
}
/* bring along the standard lsigid vector, first param marks validity of vector, 2nd is lsigid, 3rd is subsigid */
if ( lsigid ) {
root - > ac_lsigtable [ lsigid [ 0 ] ] - > virname = bcomp - > virname ;
bcomp - > lsigid [ 0 ] = 1 ;
bcomp - > lsigid [ 1 ] = lsigid [ 0 ] ;
bcomp - > lsigid [ 2 ] = lsigid [ 1 ] ;
2018-12-03 12:40:13 -05:00
} else {
2018-09-21 16:49:38 -04:00
/* sigtool */
bcomp - > lsigid [ 0 ] = 0 ;
}
/* first need to grab the subsig reference, we'll use this later to determine our offset */
buf_start = hexsig ;
2018-12-03 12:40:13 -05:00
buf_end = hexsig ;
2018-09-21 16:49:38 -04:00
2018-12-03 12:40:13 -05:00
ref_subsigid = strtol ( buf_start , ( char * * ) & buf_end , 10 ) ;
2018-09-21 16:49:38 -04:00
if ( buf_end & & buf_end [ 0 ] ! = ' ( ' ) {
cli_errmsg ( " cli_bcomp_addpatt: while byte compare subsig parsing, reference subsig id was invalid or included non-decimal character \n " ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
2020-01-06 15:45:40 -05:00
if ( ref_subsigid > MAX_LDB_SUBSIGS ) {
cli_errmsg ( " cli_bcomp_addpatt: while byte compare subsig parsing, reference subigid exceeded limits on max LDB subsigs \n " ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
2018-09-21 16:49:38 -04:00
bcomp - > ref_subsigid = ref_subsigid ;
/* use the passed hexsig buffer to find the start and ending parens and store the param length (minus starting paren) */
buf_start = buf_end ;
if ( buf_start [ 0 ] = = ' ( ' ) {
2018-12-03 12:40:13 -05:00
if ( ( buf_end = strchr ( buf_start , ' ) ' ) ) ) {
len = ( size_t ) ( buf_end - + + buf_start ) ;
} else {
2018-09-21 16:49:38 -04:00
cli_errmsg ( " cli_bcomp_addpatt: ending paren not found \n " ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
2018-12-03 12:40:13 -05:00
} else {
cli_errmsg ( " cli_bcomp_addpatt: opening paren not found \n " ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
2018-09-21 16:49:38 -04:00
}
/* make a working copy of the param buffer */
2019-08-22 16:51:01 -04:00
buf = CLI_STRNDUP ( buf_start , len ) ;
2018-09-21 16:49:38 -04:00
/* break up the new param buffer into its component strings and verify we have exactly 3 */
2018-12-03 12:40:13 -05:00
toks = cli_strtokenize ( buf , ' # ' , 3 + 1 , tokens ) ;
2018-09-21 16:49:38 -04:00
if ( 3 ! = toks ) {
cli_errmsg ( " cli_bcomp_addpatt: %zu (or more) params provided, 3 expected \n " , toks ) ;
free ( buf ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
2018-09-25 17:44:19 -04:00
tokens [ 3 ] = NULL ;
2018-09-21 16:49:38 -04:00
/* since null termination is super guaranteed thanks to strndup and cli_strokenize, we can use strtol to grab the
* offset params . this has the added benefit of letting us parse hex values too */
2018-12-03 12:40:13 -05:00
buf_end = NULL ;
2018-09-21 16:49:38 -04:00
buf_start = tokens [ 0 ] ;
switch ( buf_start [ 0 ] ) {
case ' < ' :
2018-09-24 12:24:07 -04:00
if ( ( + + buf_start ) [ 0 ] = = ' < ' ) {
2018-12-03 12:40:13 -05:00
offset_param = strtol ( + + buf_start , ( char * * ) & buf_end , 0 ) ;
if ( buf_end & & buf_end + 1 ! = tokens [ 1 ] ) {
2018-09-21 16:49:38 -04:00
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), offset parameter included invalid characters \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
free ( buf ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
/* two's-complement for negative value */
offset_param = ( ~ offset_param ) + 1 ;
2018-12-03 12:40:13 -05:00
} else {
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), shift operator not valid \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
free ( buf ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
2018-09-21 16:49:38 -04:00
break ;
case ' > ' :
2018-09-24 12:24:07 -04:00
if ( ( + + buf_start ) [ 0 ] = = ' > ' ) {
2018-12-03 12:40:13 -05:00
offset_param = strtol ( + + buf_start , ( char * * ) & buf_end , 0 ) ;
if ( buf_end & & buf_end + 1 ! = tokens [ 1 ] ) {
2018-09-21 16:49:38 -04:00
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), offset parameter included invalid characters \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
free ( buf ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
break ;
} else {
2018-12-03 12:40:13 -05:00
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), shift operator and/or offset not valid \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
free ( buf ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
2018-09-21 16:49:38 -04:00
}
case ' 0 ' :
case ' \0 ' :
offset_param = 0 ;
break ;
default :
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), shift operator included invalid characters \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
free ( buf ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
bcomp - > offset = offset_param ;
/* the byte length indicator options are stored in a bitmask--by design each option gets its own nibble */
buf_start = tokens [ 1 ] ;
2018-09-26 16:40:28 -04:00
while ( ! isdigit ( * buf_start ) ) {
switch ( * buf_start ) {
case ' h ' :
2018-10-08 13:18:09 -04:00
/* hex, decimal, auto, and binary options are mutually exclusive parameters */
if ( bcomp - > options & CLI_BCOMP_DEC | | bcomp - > options & CLI_BCOMP_BIN | | bcomp - > options & CLI_BCOMP_AUTO ) {
2018-09-26 16:40:28 -04:00
ret = CL_EMALFDB ;
} else {
bcomp - > options | = CLI_BCOMP_HEX ;
2018-12-03 12:40:13 -05:00
}
break ;
2018-10-08 13:18:09 -04:00
2018-09-26 16:40:28 -04:00
case ' d ' :
2018-10-08 13:18:09 -04:00
/* hex, decimal, auto, and binary options are mutually exclusive parameters */
2018-10-15 14:29:35 -04:00
/* decimal may not be used with little-endian. big-endian is implied. */
if ( bcomp - > options & CLI_BCOMP_HEX | | bcomp - > options & CLI_BCOMP_BIN | | bcomp - > options & CLI_BCOMP_AUTO | | bcomp - > options & CLI_BCOMP_LE ) {
2018-09-26 16:40:28 -04:00
ret = CL_EMALFDB ;
} else {
bcomp - > options | = CLI_BCOMP_DEC ;
2018-10-15 14:29:35 -04:00
bcomp - > options | = CLI_BCOMP_BE ;
2018-12-03 12:40:13 -05:00
}
break ;
2018-10-08 13:18:09 -04:00
2018-09-26 16:40:28 -04:00
case ' i ' :
2018-10-08 13:18:09 -04:00
/* hex, decimal, auto, and binary options are mutually exclusive parameters */
if ( bcomp - > options & CLI_BCOMP_HEX | | bcomp - > options & CLI_BCOMP_DEC | | bcomp - > options & CLI_BCOMP_AUTO ) {
2018-09-26 16:40:28 -04:00
ret = CL_EMALFDB ;
} else {
bcomp - > options | = CLI_BCOMP_BIN ;
2018-12-03 12:40:13 -05:00
}
break ;
2018-10-08 13:18:09 -04:00
case ' a ' :
/* for automatic hex or decimal run-time detection */
/* hex, decimal, auto, and binary options are mutually exclusive parameters */
if ( bcomp - > options & CLI_BCOMP_HEX | | bcomp - > options & CLI_BCOMP_DEC | | bcomp - > options & CLI_BCOMP_BIN ) {
ret = CL_EMALFDB ;
} else {
bcomp - > options | = CLI_BCOMP_AUTO ;
2018-12-03 12:40:13 -05:00
}
break ;
2018-10-08 13:18:09 -04:00
2018-09-26 16:40:28 -04:00
case ' l ' :
/* little and big endian options are mutually exclusive parameters */
2018-10-15 14:29:35 -04:00
/* decimal may not be used with little-endian */
if ( bcomp - > options & CLI_BCOMP_BE | | bcomp - > options & CLI_BCOMP_DEC ) {
2018-09-26 16:40:28 -04:00
ret = CL_EMALFDB ;
} else {
bcomp - > options | = CLI_BCOMP_LE ;
2018-12-03 12:40:13 -05:00
}
break ;
2018-10-08 13:18:09 -04:00
2018-09-26 16:40:28 -04:00
case ' b ' :
/* little and big endian options are mutually exclusive parameters */
if ( bcomp - > options & CLI_BCOMP_LE ) {
ret = CL_EMALFDB ;
} else {
bcomp - > options | = CLI_BCOMP_BE ;
2018-12-03 12:40:13 -05:00
}
break ;
2018-10-08 13:18:09 -04:00
2018-09-26 16:40:28 -04:00
case ' e ' :
/* for exact byte length matches */
bcomp - > options | = CLI_BCOMP_EXACT ;
break ;
2018-09-21 16:49:38 -04:00
2018-09-26 16:40:28 -04:00
default :
ret = CL_EMALFDB ;
break ;
}
2018-09-21 16:49:38 -04:00
2018-09-26 16:40:28 -04:00
if ( CL_EMALFDB = = ret ) {
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), option parameter was found invalid \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
2018-09-21 16:49:38 -04:00
free ( buf ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
2018-09-26 16:40:28 -04:00
return ret ;
}
buf_start + + ;
2018-09-21 16:49:38 -04:00
}
/* parse out the byte length parameter */
2018-12-03 12:40:13 -05:00
buf_end = NULL ;
byte_length = strtol ( buf_start , ( char * * ) & buf_end , 0 ) ;
if ( buf_end & & buf_end + 1 ! = tokens [ 2 ] ) {
2018-09-26 19:14:14 -04:00
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), byte length parameter included invalid characters \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
2018-09-21 16:49:38 -04:00
free ( buf ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
2018-09-26 19:14:14 -04:00
if ( bcomp - > options & CLI_BCOMP_BIN & & ( byte_length > CLI_BCOMP_MAX_BIN_BLEN | | CLI_BCOMP_MAX_BIN_BLEN % byte_length ) ) {
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), byte length was either too long or not a valid number of bytes \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
2018-09-26 16:40:28 -04:00
free ( buf ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
2018-10-08 13:18:09 -04:00
/* same deal with hex byte lengths */
if ( bcomp - > options & CLI_BCOMP_HEX & & ( byte_length > CLI_BCOMP_MAX_HEX_BLEN ) ) {
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), byte length was too long \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
free ( buf ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
2018-09-21 16:49:38 -04:00
bcomp - > byte_len = byte_length ;
2018-09-27 19:37:04 -04:00
/* we can have up to two comparison eval statements, each sperated by a comma, let's parse them in a separate string */
comp_buf = cli_strdup ( tokens [ 2 ] ) ;
if ( ! comp_buf ) {
cli_errmsg ( " cli_bcomp_addpatt: Unable to allocate memory for comparison buffer \n " ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMEM ;
}
/* use different buffer start and end markers so we can keep track of what we need to free later */
2018-12-03 12:40:13 -05:00
buf_start = comp_buf ;
2018-09-27 19:37:04 -04:00
comp_start = strchr ( comp_buf , ' , ' ) ;
2018-12-03 12:40:13 -05:00
comp_end = strrchr ( comp_buf , ' , ' ) ;
2018-09-21 16:49:38 -04:00
2018-09-27 19:37:04 -04:00
/* check to see if we have exactly one comma, then set our count and tokenize our string apropriately */
if ( comp_start & & comp_end ) {
if ( comp_end = = comp_start ) {
2018-12-03 12:40:13 -05:00
comp_start [ 0 ] = ' \0 ' ;
2018-09-27 19:37:04 -04:00
bcomp - > comp_count = 2 ;
} else {
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), too many commas found in comparison string \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
2018-09-21 16:49:38 -04:00
cli_bcomp_freemeta ( root , bcomp ) ;
2018-09-27 19:37:04 -04:00
free ( buf ) ;
2018-12-03 12:40:13 -05:00
free ( ( void * ) buf_start ) ;
2018-09-27 19:37:04 -04:00
return CL_EPARSE ;
}
} else {
2018-12-03 12:40:13 -05:00
comp_start = comp_buf ;
2018-09-27 19:37:04 -04:00
bcomp - > comp_count = 1 ;
2018-09-21 16:49:38 -04:00
}
2018-09-27 19:37:04 -04:00
/* allocate comp struct list space with the root structure's mempool instance */
2019-05-03 18:16:03 -04:00
bcomp - > comps = ( struct cli_bcomp_comp * * ) MPOOL_CALLOC ( root - > mempool , bcomp - > comp_count , sizeof ( struct cli_bcomp_comp * ) ) ;
2018-12-03 12:40:13 -05:00
if ( ! bcomp - > comps ) {
2018-09-27 19:37:04 -04:00
cli_errmsg ( " cli_bcomp_addpatt: unable to allocate memory for comp struct pointers \n " ) ;
2018-09-21 16:49:38 -04:00
free ( buf ) ;
2018-12-03 12:40:13 -05:00
free ( ( void * ) buf_start ) ;
2018-09-21 16:49:38 -04:00
cli_bcomp_freemeta ( root , bcomp ) ;
2018-09-27 19:37:04 -04:00
return CL_EMEM ;
2018-09-21 16:49:38 -04:00
}
2018-09-27 19:37:04 -04:00
/* loop through our new list, allocate, and parse out the needed comparison evaluation bits for this subsig */
for ( i = 0 ; i < bcomp - > comp_count ; i + + ) {
2019-05-03 18:16:03 -04:00
bcomp - > comps [ i ] = ( struct cli_bcomp_comp * ) MPOOL_CALLOC ( root - > mempool , 1 , sizeof ( struct cli_bcomp_comp ) ) ;
2018-12-03 12:40:13 -05:00
if ( ! bcomp - > virname ) {
2018-09-27 19:37:04 -04:00
cli_errmsg ( " cli_bcomp_addpatt: unable to allocate memory for comp struct \n " ) ;
free ( buf ) ;
2018-12-03 12:40:13 -05:00
free ( ( void * ) buf_start ) ;
2018-09-27 19:37:04 -04:00
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMEM ;
}
/* currently only >, <, and = are supported comparison symbols--this makes parsing very simple */
switch ( * comp_buf ) {
case ' < ' :
case ' > ' :
case ' = ' :
2018-12-03 12:40:13 -05:00
bcomp - > comps [ i ] - > comp_symbol = * comp_buf ;
break ;
2018-09-27 19:37:04 -04:00
default :
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), byte comparison symbol was invalid (>, <, = are supported operators) %s \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] , comp_buf ) ;
free ( buf ) ;
2018-12-03 12:40:13 -05:00
free ( ( void * ) buf_start ) ;
2018-09-27 19:37:04 -04:00
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
/* grab the comparison value itself */
comp_end = NULL ;
comp_buf + + ;
2018-12-03 12:40:13 -05:00
comp_val = strtoll ( comp_buf , ( char * * ) & comp_end , 0 ) ;
2018-09-27 19:37:04 -04:00
if ( * comp_end ) {
cli_errmsg ( " cli_bcomp_addpatt: while parsing (%s#%s#%s), comparison value contained invalid input \n " , tokens [ 0 ] , tokens [ 1 ] , tokens [ 2 ] ) ;
free ( buf ) ;
2018-12-03 12:40:13 -05:00
free ( ( void * ) buf_start ) ;
2018-09-27 19:37:04 -04:00
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMALFDB ;
}
bcomp - > comps [ i ] - > comp_value = comp_val ;
/* a bit of tricksy pointer stuffs which handles all count cases, taking advantage of where strtoll drops endptr */
if ( comp_end = = comp_start ) {
comp_buf = comp_start ;
comp_buf + + ;
}
2018-09-21 16:49:38 -04:00
2018-09-27 19:37:04 -04:00
/* manually verify successful pattern parsing */
bcm_dbgmsg ( " Matcher Byte Compare: (%s%ld#%c%c%s%zu#%c%ld) \n " ,
2018-12-03 12:40:13 -05:00
bcomp - > offset = = 0 ? " " : ( bcomp - > offset < 0 ? " << " : " >> " ) ,
bcomp - > offset ,
bcomp - > options & CLI_BCOMP_HEX ? ' h ' : ( bcomp - > options & CLI_BCOMP_DEC ? ' d ' : ' i ' ) ,
bcomp - > options & CLI_BCOMP_LE ? ' l ' : ' b ' ,
bcomp - > options & CLI_BCOMP_EXACT ? " e " : " " ,
bcomp - > byte_len ,
bcomp - > comps [ i ] - > comp_symbol ,
bcomp - > comps [ i ] - > comp_value ) ;
2018-09-27 19:37:04 -04:00
}
2018-09-21 16:49:38 -04:00
2018-12-03 12:40:13 -05:00
free ( ( void * ) buf_start ) ;
2018-09-27 19:37:04 -04:00
buf_start = NULL ;
2018-09-21 16:49:38 -04:00
/* add byte compare info to the root after reallocation */
2018-12-03 12:40:13 -05:00
bcomp_count = root - > bcomp_metas + 1 ;
2018-09-21 16:49:38 -04:00
/* allocate space for new meta table to store in root structure and increment number of byte compare patterns added */
2019-05-03 18:16:03 -04:00
newmetatable = ( struct cli_bcomp_meta * * ) MPOOL_REALLOC ( root - > mempool , root - > bcomp_metatable , bcomp_count * sizeof ( struct cli_bcomp_meta * ) ) ;
2018-12-03 12:40:13 -05:00
if ( ! newmetatable ) {
2018-09-21 16:49:38 -04:00
cli_errmsg ( " cli_bcomp_addpatt: Unable to allocate memory for new bcomp meta table \n " ) ;
cli_bcomp_freemeta ( root , bcomp ) ;
return CL_EMEM ;
}
2018-12-03 12:40:13 -05:00
newmetatable [ bcomp_count - 1 ] = bcomp ;
root - > bcomp_metatable = newmetatable ;
2018-09-21 16:49:38 -04:00
root - > bcomp_metas = bcomp_count ;
/* if everything went well bcomp has been totally populated, which means we can cleanup and exit */
free ( buf ) ;
return CL_SUCCESS ;
}
/**
* @ brief function to perform all byte compare matching on the file buffer
*
* @ param map the file map to perform logical byte comparison upon
* @ param res the result structure , primarily used by sigtool
* @ param root the root structure in which all byte compare lsig and subsig information is stored
* @ param mdata the ac data struct which contains offset information from recent subsig matches
* @ param ctx the clamav context struct
*
*/
2018-12-03 12:40:13 -05:00
cl_error_t cli_bcomp_scanbuf ( const unsigned char * buffer , size_t buffer_length , const char * * virname , struct cli_ac_result * * res , const struct cli_matcher * root , struct cli_ac_data * mdata , cli_ctx * ctx )
{
2018-09-21 16:49:38 -04:00
2021-05-04 11:31:44 +02:00
int64_t i = 0 , val = 0 , ret = CL_SUCCESS ;
2018-09-21 16:49:38 -04:00
uint32_t lsigid , ref_subsigid ;
2018-12-03 12:40:13 -05:00
uint32_t offset = 0 ;
uint8_t viruses_found = 0 ;
2018-09-21 16:49:38 -04:00
struct cli_bcomp_meta * bcomp = NULL ;
2018-09-24 16:04:32 -04:00
struct cli_ac_result * newres = NULL ;
2018-09-21 16:49:38 -04:00
2018-09-27 15:16:49 -04:00
uint32_t evalcnt = 0 ;
uint64_t evalids = 0 ;
2018-12-03 12:40:13 -05:00
char * subsigid = NULL ;
2018-09-27 15:16:49 -04:00
2018-09-21 16:49:38 -04:00
if ( ! ( root ) | | ! ( root - > bcomp_metas ) | | ! ( root - > bcomp_metatable ) | | ! ( mdata ) | | ! ( mdata - > offmatrix ) | | ! ( ctx ) ) {
return CL_SUCCESS ;
}
2018-12-03 12:40:13 -05:00
for ( i = 0 ; i < root - > bcomp_metas ; i + + ) {
2018-09-21 16:49:38 -04:00
2018-12-03 12:40:13 -05:00
bcomp = root - > bcomp_metatable [ i ] ;
lsigid = bcomp - > lsigid [ 1 ] ;
2018-09-21 16:49:38 -04:00
ref_subsigid = bcomp - > ref_subsigid ;
2018-09-24 16:04:32 -04:00
/* check to see if we are being run in sigtool or not */
if ( bcomp - > lsigid [ 0 ] ) {
2018-09-27 15:16:49 -04:00
subsigid = cli_calloc ( 3 , sizeof ( char ) ) ;
2020-01-06 15:45:40 -05:00
snprintf ( subsigid , 3 , " %hu " , bcomp - > ref_subsigid ) ;
2018-09-27 15:16:49 -04:00
/* verify the ref_subsigid */
2021-05-04 11:31:44 +02:00
val = cli_ac_chklsig ( subsigid , subsigid + strlen ( subsigid ) , mdata - > lsigcnt [ bcomp - > lsigid [ 1 ] ] , & evalcnt , & evalids , 0 ) ;
if ( subsigid ) {
free ( subsigid ) ;
subsigid = NULL ;
}
if ( val ! = 1 ) {
2018-09-27 15:16:49 -04:00
bcm_dbgmsg ( " cli_bcomp_scanbuf: could not verify a match for lsig reference subsigid (%s) \n " , subsigid ) ;
continue ;
}
2018-09-24 16:04:32 -04:00
/* ensures the referenced subsig matches as expected, and also ensures mdata has the needed offset */
2018-12-03 12:40:13 -05:00
if ( ( ret = lsig_sub_matched ( root , mdata , lsigid , ref_subsigid , CLI_OFF_NONE , 0 ) ) ) {
2018-09-27 15:16:49 -04:00
break ;
2018-09-24 16:04:32 -04:00
}
2018-09-21 16:49:38 -04:00
2018-09-24 16:04:32 -04:00
/* grab the needed offset using from the last matched subsig offset matrix, i.e. the match performed above */
if ( mdata - > lsigsuboff_last [ lsigid ] ) {
offset = mdata - > lsigsuboff_last [ lsigid ] [ ref_subsigid ] ;
} else {
ret = CL_SUCCESS ;
continue ;
}
2018-09-21 16:49:38 -04:00
} else {
2018-09-27 15:16:49 -04:00
/* can't run lsig_sub_matched in sigtool, and mdata isn't populated so run the raw matcher stuffs */
2018-12-03 12:40:13 -05:00
if ( res ) {
2018-09-24 16:04:32 -04:00
newres = ( struct cli_ac_result * ) cli_calloc ( 1 , sizeof ( struct cli_ac_result ) ) ;
2018-12-03 12:40:13 -05:00
if ( ! newres ) {
2018-09-27 15:16:49 -04:00
cli_errmsg ( " cli_bcomp_scanbuf: can't allocate memory for new result \n " ) ;
2018-09-24 16:04:32 -04:00
ret = CL_EMEM ;
break ;
}
2018-12-03 12:40:13 -05:00
newres - > virname = bcomp - > virname ;
2018-09-24 16:04:32 -04:00
newres - > customdata = NULL ;
2018-12-03 12:40:13 -05:00
newres - > next = * res ;
* res = newres ;
2018-09-24 16:04:32 -04:00
}
2018-09-21 16:49:38 -04:00
}
2018-09-24 13:14:07 -04:00
/* no offset available, make a best effort */
if ( offset = = CLI_OFF_NONE ) {
offset = 0 ;
}
2018-09-21 16:49:38 -04:00
/* now we have all the pieces of the puzzle, so lets do our byte compare check */
2018-09-28 17:35:12 -04:00
ret = cli_bcomp_compare_check ( buffer , buffer_length , offset , bcomp ) ;
2018-09-21 16:49:38 -04:00
/* set and append our lsig's virus name if the comparison came back positive */
if ( CL_VIRUS = = ret ) {
viruses_found = 1 ;
if ( virname ) {
* virname = bcomp - > virname ;
}
/* if we aren't scanning all, let's just exit here */
2018-09-21 17:05:56 -04:00
if ( ! SCAN_ALLMATCHES ) {
2018-09-21 16:49:38 -04:00
break ;
} else {
ret = cli_append_virus ( ctx , ( const char * ) bcomp - > virname ) ;
}
}
}
if ( ret = = CL_SUCCESS & & viruses_found ) {
return CL_VIRUS ;
}
return ret ;
}
/**
* @ brief does a numerical , logical byte comparison on a particular offset given a filemapping and the offset
*
* @ param map the file buffer we ' ll be accessing to do our comparison check
* @ param offset the offset of the referenced subsig match from the start of the file buffer
* @ param bm the byte comparison meta data struct , contains all the other info needed to do the comparison
*
*/
2018-12-03 12:40:13 -05:00
cl_error_t cli_bcomp_compare_check ( const unsigned char * f_buffer , size_t buffer_length , int offset , struct cli_bcomp_meta * bm )
2018-09-21 16:49:38 -04:00
{
2018-12-03 12:40:13 -05:00
uint32_t byte_len = 0 ;
uint32_t pad_len = 0 ;
uint32_t norm_len = 0 ;
uint32_t length = 0 ;
uint32_t i = 0 ;
2020-12-07 16:09:51 -05:00
cl_error_t ret = CL_CLEAN ;
2018-12-03 12:40:13 -05:00
uint16_t opt = 0 ;
uint16_t opt_val = 0 ;
int64_t value = 0 ;
2019-05-03 18:25:17 -04:00
int64_t bin_value = 0 ;
2018-12-03 12:40:13 -05:00
int16_t compare_check = 0 ;
unsigned char * end_buf = NULL ;
2020-08-04 15:32:24 -04:00
unsigned char * buffer = NULL ; /* Used for BE, non-binary comparisons */
unsigned char * tmp_buffer = NULL ; /* Used for LE, non-binary comparisons */
2018-09-21 16:49:38 -04:00
2018-10-23 15:28:50 -04:00
if ( ! f_buffer | | ! bm ) {
2018-09-26 19:22:13 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: a param is null \n " ) ;
2020-12-07 16:09:51 -05:00
ret = CL_ENULLARG ;
goto done ;
2018-09-25 17:44:19 -04:00
}
byte_len = bm - > byte_len ;
2018-12-03 12:40:13 -05:00
length = buffer_length ;
opt = bm - > options ;
2018-09-25 17:44:19 -04:00
2018-09-21 16:49:38 -04:00
/* ensure we won't run off the end of the file buffer */
2019-06-04 12:17:24 -07:00
if ( ! ( offset + bm - > offset + byte_len < = length ) ) {
bcm_dbgmsg ( " cli_bcomp_compare_check: %u bytes requested at offset %zu would go past file buffer of %u \n " , byte_len , ( offset + bm - > offset ) , length ) ;
2020-12-07 16:09:51 -05:00
goto done ;
2019-06-04 12:17:24 -07:00
}
if ( ! ( offset + bm - > offset > 0 ) ) {
bcm_dbgmsg ( " cli_bcomp_compare_check: negative offset would underflow buffer \n " ) ;
2020-12-07 16:09:51 -05:00
goto done ;
2018-09-21 16:49:38 -04:00
}
/* jump to byte compare offset, then store off specified bytes into a null terminated buffer */
offset + = bm - > offset ;
2018-10-23 15:28:50 -04:00
f_buffer + = offset ;
2018-09-28 17:35:12 -04:00
2018-10-23 15:28:50 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: literal extracted bytes before comparison %.*s \n " , byte_len , f_buffer ) ;
/* normalize buffer for whitespace */
opt_val = opt & 0x000F ;
2018-12-03 12:40:13 -05:00
if ( ! ( opt_val & CLI_BCOMP_BIN ) ) {
2018-10-23 15:28:50 -04:00
buffer = cli_bcomp_normalize_buffer ( f_buffer , byte_len , & pad_len , opt , 1 ) ;
if ( NULL = = buffer ) {
cli_errmsg ( " cli_bcomp_compare_check: unable to whitespace normalize temp buffer, allocation failed \n " ) ;
2020-12-07 16:09:51 -05:00
ret = CL_EMEM ;
goto done ;
2018-10-23 15:28:50 -04:00
}
/* adjust byte_len accordingly */
byte_len - = pad_len ;
}
2018-10-08 16:57:03 -04:00
/* normalize buffer for little endian vals */
opt_val = opt & 0x00F0 ;
if ( opt_val = = CLI_BCOMP_LE ) {
opt_val = opt & 0x000F ;
2018-12-03 12:40:13 -05:00
if ( ! ( opt_val & CLI_BCOMP_BIN ) ) {
2018-10-25 14:30:07 -04:00
tmp_buffer = cli_bcomp_normalize_buffer ( buffer , byte_len , NULL , opt , 0 ) ;
2018-10-08 16:57:03 -04:00
if ( NULL = = tmp_buffer ) {
2018-10-23 15:28:50 -04:00
cli_errmsg ( " cli_bcomp_compare_check: unable to normalize temp, allocation failed \n " ) ;
2020-12-07 16:09:51 -05:00
ret = CL_EMEM ;
goto done ;
2018-10-08 13:18:09 -04:00
}
2018-10-08 16:57:03 -04:00
}
}
2018-10-08 13:18:09 -04:00
2018-10-08 16:57:03 -04:00
opt_val = opt ;
if ( opt_val & CLI_BCOMP_AUTO ) {
2018-10-25 14:30:07 -04:00
opt = cli_bcomp_chk_hex ( buffer , opt_val , byte_len , 0 ) ;
2018-10-08 16:57:03 -04:00
}
2018-10-08 13:18:09 -04:00
2018-10-08 16:57:03 -04:00
/* grab the first byte to handle byte length options to convert the string appropriately */
2018-12-03 12:40:13 -05:00
switch ( opt & 0x00FF ) {
2018-09-21 16:49:38 -04:00
/*hl*/
case CLI_BCOMP_HEX | CLI_BCOMP_LE :
2018-10-24 16:17:40 -04:00
if ( byte_len ! = 1 ) {
norm_len = ( byte_len % 2 ) = = 0 ? byte_len : byte_len + 1 ;
} else {
norm_len = 1 ;
}
2018-09-26 16:40:28 -04:00
errno = 0 ;
2018-12-03 12:40:13 -05:00
value = cli_strntol ( ( char * ) tmp_buffer , norm_len , ( char * * ) & end_buf , 16 ) ;
2018-09-26 16:40:28 -04:00
if ( ( ( ( value = = LONG_MAX ) | | ( value = = LONG_MIN ) ) & & errno = = ERANGE ) | | NULL = = end_buf ) {
2018-09-26 19:22:13 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: little endian hex conversion unsuccessful \n " ) ;
2020-12-07 16:09:51 -05:00
goto done ;
2018-09-21 16:49:38 -04:00
}
2018-09-26 16:40:28 -04:00
/*hle*/
if ( opt & CLI_BCOMP_EXACT ) {
2018-12-03 12:40:13 -05:00
if ( tmp_buffer + byte_len ! = end_buf | | pad_len ! = 0 ) {
2018-09-26 16:40:28 -04:00
2018-09-26 19:22:13 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: couldn't extract the exact number of requested bytes \n " ) ;
2020-12-07 16:09:51 -05:00
goto done ;
2018-09-26 16:40:28 -04:00
}
}
2018-09-21 16:49:38 -04:00
break ;
2018-12-03 12:40:13 -05:00
/*hb*/
2018-09-21 16:49:38 -04:00
case CLI_BCOMP_HEX | CLI_BCOMP_BE :
2018-12-03 12:40:13 -05:00
value = cli_strntol ( ( char * ) buffer , byte_len , ( char * * ) & end_buf , 16 ) ;
2018-09-26 16:40:28 -04:00
if ( ( ( ( value = = LONG_MAX ) | | ( value = = LONG_MIN ) ) & & errno = = ERANGE ) | | NULL = = end_buf ) {
2018-09-26 19:22:13 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: big endian hex conversion unsuccessful \n " ) ;
2020-12-07 16:09:51 -05:00
goto done ;
2018-09-21 16:49:38 -04:00
}
2018-09-26 16:40:28 -04:00
/*hbe*/
if ( opt & CLI_BCOMP_EXACT ) {
2018-12-03 12:40:13 -05:00
if ( buffer + byte_len ! = end_buf | | pad_len ! = 0 ) {
2018-09-21 16:49:38 -04:00
2018-09-26 19:22:13 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: couldn't extract the exact number of requested bytes \n " ) ;
2020-12-07 16:09:51 -05:00
goto done ;
2018-09-26 16:40:28 -04:00
}
}
2018-09-21 16:49:38 -04:00
break ;
/*dl*/
case CLI_BCOMP_DEC | CLI_BCOMP_LE :
2018-10-15 14:29:35 -04:00
/* it may be possible for the auto option to proc this */
2018-10-25 14:30:07 -04:00
2018-10-15 14:29:35 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: auto detection found ascii decimal for specified little endian byte extraction, which is unsupported \n " ) ;
2020-12-07 16:09:51 -05:00
goto done ;
2018-09-21 16:49:38 -04:00
break ;
/*db*/
case CLI_BCOMP_DEC | CLI_BCOMP_BE :
2018-12-03 12:40:13 -05:00
value = cli_strntol ( ( char * ) buffer , byte_len , ( char * * ) & end_buf , 10 ) ;
2018-09-26 16:40:28 -04:00
if ( ( ( ( value = = LONG_MAX ) | | ( value = = LONG_MIN ) ) & & errno = = ERANGE ) | | NULL = = end_buf ) {
2018-09-21 16:49:38 -04:00
2018-09-26 19:22:13 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: big endian decimal conversion unsuccessful \n " ) ;
2020-12-07 16:09:51 -05:00
goto done ;
2018-09-21 16:49:38 -04:00
}
2018-09-26 16:40:28 -04:00
/*dbe*/
if ( opt & CLI_BCOMP_EXACT ) {
2018-12-03 12:40:13 -05:00
if ( buffer + byte_len ! = end_buf | | pad_len ! = 0 ) {
2018-09-26 16:40:28 -04:00
2018-09-26 19:22:13 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: couldn't extract the exact number of requested bytes \n " ) ;
2020-12-07 16:09:51 -05:00
goto done ;
2018-09-26 16:40:28 -04:00
}
}
2018-09-21 16:49:38 -04:00
break ;
2018-09-27 15:16:49 -04:00
2018-09-26 19:14:14 -04:00
/*il*/
2018-09-26 16:40:28 -04:00
case CLI_BCOMP_BIN | CLI_BCOMP_LE :
2018-09-26 19:14:14 -04:00
/* exact byte_length option is implied for binary extraction */
switch ( byte_len ) {
2018-12-03 12:40:13 -05:00
case 1 :
2019-05-03 18:25:17 -04:00
bin_value = ( int64_t ) ( * ( uint8_t * ) f_buffer ) ;
2018-12-03 12:40:13 -05:00
break ;
case 2 :
2019-05-03 18:25:17 -04:00
bin_value = ( int64_t ) le16_to_host ( * ( uint16_t * ) f_buffer ) ;
2018-12-03 12:40:13 -05:00
break ;
case 4 :
2019-05-03 18:25:17 -04:00
bin_value = ( int64_t ) le32_to_host ( * ( uint32_t * ) f_buffer ) ;
2018-12-03 12:40:13 -05:00
break ;
case 8 :
2019-05-03 18:25:17 -04:00
bin_value = ( int64_t ) le64_to_host ( * ( uint64_t * ) f_buffer ) ;
2018-12-03 12:40:13 -05:00
break ;
2018-09-26 19:14:14 -04:00
default :
2018-09-26 19:22:13 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: invalid byte size for binary integer field (%u) \n " , byte_len ) ;
2020-12-07 16:09:51 -05:00
ret = CL_EARG ;
goto done ;
2018-09-26 19:14:14 -04:00
}
2018-09-26 16:40:28 -04:00
break ;
2018-09-27 15:16:49 -04:00
2018-09-26 19:14:14 -04:00
/*ib*/
2018-09-26 16:40:28 -04:00
case CLI_BCOMP_BIN | CLI_BCOMP_BE :
2018-09-26 19:14:14 -04:00
/* exact byte_length option is implied for binary extraction */
switch ( byte_len ) {
2018-12-03 12:40:13 -05:00
case 1 :
2019-05-03 18:25:17 -04:00
bin_value = ( int64_t ) ( * ( uint8_t * ) f_buffer ) ;
2018-12-03 12:40:13 -05:00
break ;
case 2 :
2019-05-03 18:25:17 -04:00
bin_value = ( int64_t ) be16_to_host ( * ( uint16_t * ) f_buffer ) ;
2018-12-03 12:40:13 -05:00
break ;
case 4 :
2019-05-03 18:25:17 -04:00
bin_value = ( int64_t ) be32_to_host ( * ( uint32_t * ) f_buffer ) ;
2018-12-03 12:40:13 -05:00
break ;
case 8 :
2019-05-03 18:25:17 -04:00
bin_value = ( int64_t ) be64_to_host ( * ( uint64_t * ) f_buffer ) ;
2018-12-03 12:40:13 -05:00
break ;
2018-09-26 19:14:14 -04:00
default :
2018-09-26 19:22:13 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: invalid byte size for binary integer field (%u) \n " , byte_len ) ;
2020-12-07 16:09:51 -05:00
ret = CL_EARG ;
goto done ;
2018-09-26 19:14:14 -04:00
}
2018-09-26 16:40:28 -04:00
break ;
2018-09-27 15:16:49 -04:00
2018-09-21 16:49:38 -04:00
default :
2018-10-08 16:57:03 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: options were found invalid \n " ) ;
2020-12-07 16:09:51 -05:00
ret = CL_ENULLARG ;
goto done ;
2018-10-25 14:30:07 -04:00
}
2018-09-21 16:49:38 -04:00
/* do the actual comparison */
2018-09-27 19:37:04 -04:00
for ( i = 0 ; i < bm - > comp_count ; i + + ) {
if ( bm - > comps & & bm - > comps [ i ] ) {
switch ( bm - > comps [ i ] - > comp_symbol ) {
case ' > ' :
2018-11-14 16:08:59 -05:00
if ( opt & CLI_BCOMP_BIN ) {
compare_check = ( bin_value > bm - > comps [ i ] - > comp_value ) ;
} else {
compare_check = ( value > bm - > comps [ i ] - > comp_value ) ;
}
if ( compare_check ) {
bcm_dbgmsg ( " cli_bcomp_compare_check: extracted value (%ld) greater than comparison value (%ld) \n " , ( opt & CLI_BCOMP_BIN ) ? bin_value : value , bm - > comps [ i ] - > comp_value ) ;
2018-09-27 19:37:04 -04:00
ret = CL_VIRUS ;
} else {
ret = CL_CLEAN ;
}
break ;
2018-09-21 16:49:38 -04:00
2018-09-27 19:37:04 -04:00
case ' < ' :
2018-11-14 16:08:59 -05:00
if ( opt & CLI_BCOMP_BIN ) {
compare_check = ( bin_value < bm - > comps [ i ] - > comp_value ) ;
} else {
compare_check = ( value < bm - > comps [ i ] - > comp_value ) ;
}
if ( compare_check ) {
bcm_dbgmsg ( " cli_bcomp_compare_check: extracted value (%ld) less than comparison value (%ld) \n " , ( opt & CLI_BCOMP_BIN ) ? bin_value : value , bm - > comps [ i ] - > comp_value ) ;
2018-09-27 19:37:04 -04:00
ret = CL_VIRUS ;
} else {
ret = CL_CLEAN ;
}
break ;
2018-09-21 16:49:38 -04:00
2018-09-27 19:37:04 -04:00
case ' = ' :
2018-11-14 16:08:59 -05:00
if ( opt & CLI_BCOMP_BIN ) {
compare_check = ( bin_value = = bm - > comps [ i ] - > comp_value ) ;
} else {
compare_check = ( value = = bm - > comps [ i ] - > comp_value ) ;
}
if ( compare_check ) {
bcm_dbgmsg ( " cli_bcomp_compare_check: extracted value (%ld) equal to comparison value (%ld) \n " , ( opt & CLI_BCOMP_BIN ) ? bin_value : value , bm - > comps [ i ] - > comp_value ) ;
2018-09-27 19:37:04 -04:00
ret = CL_VIRUS ;
} else {
ret = CL_CLEAN ;
}
break ;
2018-09-21 16:49:38 -04:00
2018-09-27 19:37:04 -04:00
default :
bcm_dbgmsg ( " cli_bcomp_compare_check: comparison symbol (%c) invalid \n " , bm - > comps [ i ] - > comp_symbol ) ;
2020-12-07 16:09:51 -05:00
ret = CL_ENULLARG ;
goto done ;
2018-09-21 16:49:38 -04:00
}
2018-09-27 19:37:04 -04:00
if ( CL_CLEAN = = ret ) {
/* comparison was not successful */
2018-11-14 16:08:59 -05:00
bcm_dbgmsg ( " cli_bcomp_compare_check: extracted value (%ld) was not %c %ld \n " , ( opt & CLI_BCOMP_BIN ) ? bin_value : value , bm - > comps [ i ] - > comp_symbol , bm - > comps [ i ] - > comp_value ) ;
2020-12-07 16:09:51 -05:00
goto done ;
2018-09-27 19:37:04 -04:00
}
}
2018-09-21 16:49:38 -04:00
}
2018-11-14 16:08:59 -05:00
2020-12-07 16:09:51 -05:00
done :
if ( NULL ! = tmp_buffer ) {
free ( tmp_buffer ) ;
}
if ( NULL ! = buffer ) {
free ( buffer ) ;
}
2018-09-27 19:37:04 -04:00
return ret ;
2018-09-21 16:49:38 -04:00
}
2018-10-23 15:28:50 -04:00
/**
* @ brief checks to see if an ascii buffer should be considered hex or not
*
* @ param buffer is the buffer to evaluate
* @ param opts the bcomp opts bitfield to set / evaluate during the check
* @ param len the length of the buffer , must be larger than 3 bytes
* @ param check_only specifies whether to return true / false or the modified opt value
*
* @ return if check only is set , it will return true or false , otherwise it returns a modifiied byte compare bitfield
*/
2018-12-03 12:40:13 -05:00
uint16_t cli_bcomp_chk_hex ( const unsigned char * buffer , uint16_t opt , uint32_t len , uint32_t check_only )
{
2018-10-23 15:28:50 -04:00
uint16_t check = 0 ;
if ( ! buffer | | len < 3 ) {
2018-10-24 12:30:36 -04:00
if ( buffer & & len < 3 ) {
if ( ( opt & 0x00F0 ) & CLI_BCOMP_AUTO ) {
opt | = CLI_BCOMP_DEC ;
opt ^ = CLI_BCOMP_AUTO ;
}
}
2018-10-23 15:28:50 -04:00
return check_only ? check : opt ;
}
2018-12-03 12:40:13 -05:00
if ( ! strncmp ( ( char * ) buffer , " 0x " , 2 ) | | ! strncmp ( ( char * ) buffer , " 0X " , 2 ) ) {
2018-10-23 15:28:50 -04:00
opt | = CLI_BCOMP_HEX ;
check = 1 ;
} else {
opt | = CLI_BCOMP_DEC ;
check = 0 ;
}
opt ^ = CLI_BCOMP_AUTO ;
return check_only ? check : opt ;
}
/**
* @ brief multipurpose buffer normalization support function for bytcompare
*
* Currently can be used to normalize a little endian hex buffer to big endian .
* Can also be used to trim whitespace from the front of the buffer .
*
* @ param buffer is the ascii bytes which are to be normalized
* @ param byte_len is the length of these bytes
* @ param pad_len if the address passed is non - null function will store the amount of whitespace found in bytes
* @ param opt the byte compare option bitfield
* @ param whitespace_only if true will only do whitespace normalization , will not perform whitespace
* normalization if set to no
*
* @ return returns an allocated , normalized buffer or NULL if an allocation error has occurred
*/
2018-12-03 12:40:13 -05:00
unsigned char * cli_bcomp_normalize_buffer ( const unsigned char * buffer , uint32_t byte_len , uint32_t * pad_len , uint16_t opt , uint16_t whitespace_only )
{
uint32_t norm_len = 0 ;
uint32_t pad = 0 ;
uint32_t i = 0 ;
uint16_t opt_val = 0 ;
uint16_t hex = 0 ;
unsigned char * tmp_buffer = NULL ;
2018-10-23 15:28:50 -04:00
if ( ! buffer ) {
cli_errmsg ( " cli_bcomp_compare_check: unable to normalize temp buffer, params null \n " ) ;
return NULL ;
}
if ( whitespace_only ) {
2018-12-03 12:40:13 -05:00
for ( i = 0 ; i < byte_len ; i + + ) {
2018-10-23 15:28:50 -04:00
if ( isspace ( buffer [ i ] ) ) {
bcm_dbgmsg ( " cli_bcomp_compare_check: buffer has whitespace \n " ) ;
pad + + ;
} else {
/* break on first non-padding whitespace */
break ;
}
}
/* keep in mind byte_len is a stack variable so this won't change byte_len in our calling functioning */
2018-12-03 12:40:13 -05:00
byte_len = byte_len - pad ;
tmp_buffer = cli_calloc ( byte_len + 1 , sizeof ( char ) ) ;
2018-10-23 15:28:50 -04:00
if ( NULL = = tmp_buffer ) {
cli_errmsg ( " cli_bcomp_compare_check: unable to allocate memory for whitespace normalized temp buffer \n " ) ;
return NULL ;
}
2018-12-03 12:40:13 -05:00
memset ( tmp_buffer , ' 0 ' , byte_len + 1 ) ;
memcpy ( tmp_buffer , buffer + pad , byte_len ) ;
2018-10-23 15:28:50 -04:00
tmp_buffer [ byte_len ] = ' \0 ' ;
if ( pad_len ) {
* pad_len = pad ;
}
return tmp_buffer ;
}
opt_val = opt & 0x000F ;
if ( opt_val & CLI_BCOMP_HEX | | opt_val & CLI_BCOMP_AUTO ) {
2020-08-04 15:32:24 -04:00
unsigned char * hex_buffer ;
2018-12-03 12:40:13 -05:00
norm_len = ( byte_len % 2 ) = = 0 ? byte_len : byte_len + 1 ;
tmp_buffer = cli_calloc ( norm_len + 1 , sizeof ( char ) ) ;
2018-10-23 15:28:50 -04:00
if ( NULL = = tmp_buffer ) {
cli_errmsg ( " cli_bcomp_compare_check: unable to allocate memory for normalized temp buffer \n " ) ;
return NULL ;
}
2018-12-03 12:40:13 -05:00
hex_buffer = cli_calloc ( norm_len + 1 , sizeof ( char ) ) ;
if ( NULL = = hex_buffer ) {
2018-10-23 15:28:50 -04:00
free ( tmp_buffer ) ;
cli_errmsg ( " cli_bcomp_compare_check: unable to reallocate memory for hex buffer \n " ) ;
return NULL ;
}
2018-12-03 12:40:13 -05:00
memset ( tmp_buffer , ' 0 ' , norm_len + 1 ) ;
memset ( hex_buffer , ' 0 ' , norm_len + 1 ) ;
2018-10-23 15:28:50 -04:00
if ( byte_len = = 1 ) {
tmp_buffer [ 0 ] = buffer [ 0 ] ;
} else {
if ( norm_len = = byte_len + 1 ) {
opt_val = opt ;
if ( cli_bcomp_chk_hex ( buffer , opt_val , byte_len , 1 ) ) {
2018-12-03 12:40:13 -05:00
memcpy ( hex_buffer + 3 , buffer + 2 , byte_len - 2 ) ;
2018-10-23 15:28:50 -04:00
hex_buffer [ 0 ] = ' x ' ;
} else {
2018-12-03 12:40:13 -05:00
memcpy ( hex_buffer + 1 , buffer , byte_len ) ;
2018-10-23 15:28:50 -04:00
}
} else {
opt_val = opt ;
memcpy ( hex_buffer , buffer , byte_len ) ;
if ( cli_bcomp_chk_hex ( buffer , opt_val , byte_len , 1 ) ) {
hex_buffer [ 0 ] = ' x ' ;
}
}
2018-12-03 12:40:13 -05:00
for ( i = 0 ; i < norm_len ; i = i + 2 ) {
if ( ( ( int32_t ) norm_len - ( int32_t ) i ) - 2 > = 0 ) {
2018-10-23 15:28:50 -04:00
/* 0000BA -> B0000A */
2018-12-03 12:40:13 -05:00
if ( isxdigit ( hex_buffer [ norm_len - i - 2 ] ) | | toupper ( hex_buffer [ norm_len - i - 2 ] ) = = ' X ' ) {
if ( isxdigit ( hex_buffer [ norm_len - i - 2 ] ) ) {
2018-10-23 15:28:50 -04:00
hex = 1 ;
}
2018-12-03 12:40:13 -05:00
tmp_buffer [ i ] = hex_buffer [ norm_len - i - 2 ] ;
2018-10-23 15:28:50 -04:00
} else {
/* non-hex detected, our current buffer is invalid so zero it out and continue */
2018-12-03 12:40:13 -05:00
memset ( tmp_buffer , ' 0 ' , norm_len + 1 ) ;
2018-10-23 15:28:50 -04:00
hex = 0 ;
2018-10-24 12:30:36 -04:00
/* nibbles after this are non-good, so skip them */
continue ;
2018-10-23 15:28:50 -04:00
}
}
/* 0000BA -> 0A00B0 */
2018-12-03 12:40:13 -05:00
if ( isxdigit ( hex_buffer [ norm_len - i - 1 ] ) | | toupper ( hex_buffer [ norm_len - i - 1 ] ) = = ' X ' ) {
if ( isxdigit ( hex_buffer [ norm_len - i - 2 ] ) ) {
hex = 1 ;
}
tmp_buffer [ i + 1 ] = hex_buffer [ norm_len - i - 1 ] ;
2018-10-23 15:28:50 -04:00
} else {
/* non-hex detected, our current buffer is invalid so zero it out and continue */
2018-12-03 12:40:13 -05:00
memset ( tmp_buffer , ' 0 ' , norm_len + 1 ) ;
2018-10-23 15:28:50 -04:00
hex = 0 ;
}
}
}
2019-06-04 09:49:37 -07:00
tmp_buffer [ norm_len ] = ' \0 ' ;
2018-10-24 16:17:40 -04:00
bcm_dbgmsg ( " cli_bcomp_compare_check: normalized extracted bytes before comparison %.*s \n " , norm_len , tmp_buffer ) ;
2020-08-04 15:32:24 -04:00
free ( hex_buffer ) ;
2018-10-23 15:28:50 -04:00
}
return tmp_buffer ;
}
2018-09-21 16:49:38 -04:00
/**
* @ brief cleans up the byte compare data struct
*
* @ param root the root matcher struct whose mempool instance the bcomp struct has been allocated with
* @ param bm the bcomp struct to be freed
*
*/
2018-12-03 12:40:13 -05:00
void cli_bcomp_freemeta ( struct cli_matcher * root , struct cli_bcomp_meta * bm )
{
2018-09-21 16:49:38 -04:00
2018-09-27 19:37:04 -04:00
int i = 0 ;
2018-12-03 12:40:13 -05:00
if ( ! root | | ! bm ) {
2018-09-21 16:49:38 -04:00
return ;
}
2018-12-03 12:40:13 -05:00
2018-09-21 16:49:38 -04:00
if ( bm - > virname ) {
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( root - > mempool , bm - > virname ) ;
2018-09-21 16:49:38 -04:00
bm - > virname = NULL ;
}
2018-09-27 19:37:04 -04:00
/* can never have more than 2 */
if ( bm - > comps ) {
for ( i = 0 ; i < 2 ; i + + ) {
if ( bm - > comps [ i ] ) {
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( root - > mempool , bm - > comps [ i ] ) ;
2018-09-27 19:37:04 -04:00
bm - > comps [ i ] = NULL ;
}
}
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( root - > mempool , bm - > comps ) ;
2018-09-27 19:37:04 -04:00
bm - > comps = NULL ;
}
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( root - > mempool , bm ) ;
2018-09-21 16:49:38 -04:00
bm = NULL ;
return ;
}