Bug #8948
openfirewall: app-layer hook rules for IMAP load without error but never match (IMAP is detection-only)
Description
In firewall mode a rule can hook an application-layer state, e.g. accept:hook <proto>:request_started or drop:flow <proto>:request_started. For IMAP these rules load without any error or warning, but they are completely inert: they never match, and the app-layer firewall policy never engages for an IMAP flow.
The reason is that IMAP is detection-only in Suricata. src/app-layer-imap.c registers protocol-detection patterns but registers no parser, no transactions and no progress states. Firewall app-layer hooks bind to a protocol's progress states, so for IMAP there is no state for the hook to bind to and the hook is never reached.
Net effect: an operator who writes a firewall rule to control IMAP at the app layer (for example drop:flow imap:request_started to block IMAP) gets a rule that Suricata silently accepts and that has zero effect. The IMAP flow is still detected as app_proto: imap and passes untouched. This is misleading and is a latent policy/security gap, because the authored control is never enforced and there is no diagnostic to say so.
Steps to reproduce¶
Firewall ruleset (firewall.rules):
# Accept the TCP session at the packet level so packets flow and the flow # reaches app-layer classification. accept:hook tcp:all any any <> any any (flow:not_established; alert; sid:1000;) accept:hook tcp:all any any <> any any (flow:established; alert; sid:1001;) # Intended policy: drop every IMAP flow at the request hook. drop:flow imap:request_started any any -> any any (alert; sid:2000;)
Replay an IMAP session (e.g. tests/imap-detection/input.pcap) in simulated IPS mode:
suricata --simulate-ips -k none -c suricata.yaml \
-r input.pcap --firewall-rules-exclusive firewall.rules
Expected behaviour¶
Either of the following would be acceptable:
- The
drop:flow imap:request_startedrule enforces the policy: the IMAP flow is dropped,sid:2000alerts (alert.action: blocked), first dropdrop.reason: "firewall rules", andstats.firewall.drop_reason.rules >= 1; or - Suricata rejects or warns at rule load that IMAP exposes no app-layer hook/progress state to bind to, so the operator knows the rule can never take effect (analogous to how other invalid hook specifications are reported).
Actual behaviour¶
- The rule loads with no error and no warning.
sid:2000never fires -- no alert is generated for it.- Nothing is dropped: no
event_type: drop,stats.firewall.blocked: 0,stats.firewall.drop_reason.rules: 0,default_app_policy: 0,flow_drop: 0;stats.ips.blocked: 0. - The flow is still detected as IMAP: one
event_type: flowwithapp_proto: imap, and the packet-level hook alerts (sid:1001) carryapp_proto: imap.
Observed on the pcap above: stats.firewall.accepted: 106, stats.firewall.blocked: 0; sid:1000 x3, sid:1001 x103, sid:2000 x0.
Regression test¶
A suricata-verify test that asserts the expected behaviour (the drop:flow imap:request_started rule blocks the IMAP flow). It currently fails, reproducing the bug, and will start passing once the issue is fixed:
- (suricata-verify PR: https://github.com/OISF/suricata-verify/pull/3319)
The test passes a control check (the flow is still detected as app_proto: imap) and then asserts the two currently-failing expectations:
- filter: # the drop rule must fire and block
count: 1
match:
event_type: alert
alert.signature_id: 2000
alert.engine: fw
alert.action: blocked
app_proto: imap
- stats: # the flow must actually be dropped
firewall.drop_reason.rules.__gte: 1
firewall.blocked.__gte: 1
Open question for maintainers¶
Is the intended contract that firewall app-layer hooks may only be used with protocols that register app-layer progress states? If so, should the rule loader reject (or at least warn on) an app-layer hook targeting a detection-only protocol such as IMAP, so that a rule which can never match is not silently accepted? Alternatively, should detection-only protocols expose minimal progress states so that basic request/response hooks are usable in firewall mode?