@ -109,6 +109,23 @@ typedef struct SignatureParser_ {
char opts [ DETECT_MAX_RULE_SIZE ] ;
} SignatureParser ;
/** Valid action scopes per firewall hook class. */
enum DetectFirewallPolicyClass {
DETECT_FIREWALL_POLICY_CLASS_PACKET ,
DETECT_FIREWALL_POLICY_CLASS_APP
} ;
static const uint8_t fw_packet_hook_scopes [ ] = {
ACTION_SCOPE_PACKET ,
ACTION_SCOPE_HOOK ,
ACTION_SCOPE_FLOW ,
} ;
static const uint8_t fw_app_hook_scopes [ ] = {
ACTION_SCOPE_FLOW ,
ACTION_SCOPE_TX ,
ACTION_SCOPE_HOOK ,
} ;
/** \brief max length of a firewall.policies YAML config path */
# define FW_POLICY_YAML_PATH_MAX 320
/** \brief max length of a single YAML path leaf segment (a hook name) */
@ -3930,6 +3947,59 @@ static int DoParsePolicy(const char *policy_name, struct DetectFirewallPolicy *p
return 1 ;
}
static bool FirewallScopeValidForClass ( uint8_t scope , enum DetectFirewallPolicyClass pol_class )
{
const uint8_t * set = NULL ;
size_t n = 0 ;
switch ( pol_class ) {
case DETECT_FIREWALL_POLICY_CLASS_PACKET :
set = fw_packet_hook_scopes ;
n = ARRAY_SIZE ( fw_packet_hook_scopes ) ;
break ;
case DETECT_FIREWALL_POLICY_CLASS_APP :
set = fw_app_hook_scopes ;
n = ARRAY_SIZE ( fw_app_hook_scopes ) ;
break ;
default :
FatalError ( " Invalid firewall policy class %u " , ( unsigned ) pol_class ) ;
}
for ( size_t i = 0 ; i < n ; i + + ) {
if ( set [ i ] = = scope ) {
return true ;
}
}
return false ;
}
/**
* \ brief Render the valid scopes for a hook class to a string .
*/
static void FirewallScopeHintForClass (
enum DetectFirewallPolicyClass pol_class , char * out , size_t out_size )
{
const uint8_t * set = NULL ;
size_t n = 0 ;
switch ( pol_class ) {
case DETECT_FIREWALL_POLICY_CLASS_PACKET :
set = fw_packet_hook_scopes ;
n = ARRAY_SIZE ( fw_packet_hook_scopes ) ;
break ;
case DETECT_FIREWALL_POLICY_CLASS_APP :
set = fw_app_hook_scopes ;
n = ARRAY_SIZE ( fw_app_hook_scopes ) ;
break ;
default :
FatalError ( " Invalid firewall policy class %u " , ( unsigned ) pol_class ) ;
}
out [ 0 ] = ' \0 ' ;
for ( size_t i = 0 ; i < n ; i + + ) {
if ( ( i > 0 & & strlcat ( out , " / " , out_size ) > = out_size ) | |
strlcat ( out , ActionScopeToString ( ( enum ActionScope ) set [ i ] ) , out_size ) > = out_size ) {
FatalError ( " firewall policy scope hint too long " ) ;
}
}
}
/**
* \ brief Append a unique inheritance tier to the chain of firewall policies to query .
*/
@ -3962,13 +4032,16 @@ static void ATTR_FMT_PRINTF(2, 3)
/**
* \ brief Resolve a firewall policy from its config path chain .
*
* The first path in the chain that has a policy configured wins .
* The first path in the chain that has a policy configured wins , with its
* action scope validated against the target hook class .
*
* \ retval 1 a config source was used and stored in \ p out
* \ retval 0 no source present , \ p out is unmodified
* \ retval - 1 parse error , e . g . an empty policy
* \ retval - 1 parse error , e . g . an empty policy , or invalid scope for the target class
*/
static int ResolveFirewallPolicy ( struct DetectFirewallPolicy * out , const FirewallPolicyChain * chain )
static int ResolveFirewallPolicy ( struct DetectFirewallPolicy * out ,
enum DetectFirewallPolicyClass pol_class , const FirewallPolicyChain * chain )
{
for ( uint8_t i = 0 ; i < chain - > len ; i + + ) {
const char * path = chain - > path [ i ] ;
@ -3982,6 +4055,13 @@ static int ResolveFirewallPolicy(struct DetectFirewallPolicy *out, const Firewal
SCLogError ( " %s: policy is set but empty " , path ) ;
return - 1 ;
}
if ( ! FirewallScopeValidForClass ( tmp . action_scope , pol_class ) ) {
char hint [ 32 ] ; // space to combine ActionScopeToString results
FirewallScopeHintForClass ( pol_class , hint , sizeof ( hint ) ) ;
SCLogError ( " %s: action scope ( \" %s \" ) is not valid. Valid scopes: %s " , path ,
ActionScopeToString ( tmp . action_scope ) , hint ) ;
return - 1 ;
}
* out = tmp ;
return 1 ;
}
@ -4046,7 +4126,7 @@ static int DoParseAppPolicy(const char *prefix, const AppProto app_proto, const
app_pol - > action = ACTION_DROP ;
app_pol - > action_scope = ACTION_SCOPE_FLOW ;
int r = ResolveFirewallPolicy ( app_pol , & chain ) ;
int r = ResolveFirewallPolicy ( app_pol , DETECT_FIREWALL_POLICY_CLASS_APP , & chain ) ;
if ( r < 0 ) {
return - 1 ;
}
@ -4116,7 +4196,7 @@ static int DetectFirewallLoadPacketPolicy(struct DetectFirewallPolicies *fw_poli
FirewallPolicyChainAdd ( & chain , " %s.default-policy " , prefix ) ;
struct DetectFirewallPolicy * pol = & fw_policies - > pkt [ id ] ; // built-in default
int r = ResolveFirewallPolicy ( pol , & chain ) ;
int r = ResolveFirewallPolicy ( pol , DETECT_FIREWALL_POLICY_CLASS_PACKET , & chain ) ;
if ( r < 0 ) {
return - 1 ;
}