Bug #9423
opendetect/ipopts: ipopts:any never matches because 0xffff is compared as a required mask
Description
Summary¶
The rule parser accepts ipopts:any, but DetectIpOptsMatch cannot match any opts_set value produced by the stock IPv4 options decoder. The documented behavior is to match when any IP options are present.
Version examined: source tag suricata-8.0.7.
Example rule:
Root cause¶
In src/detect-ipopts.c, the ipopts table maps "any" to 0xffff. DetectIpOptsParse copies this value to de->ipopt. DetectIpOptsMatch then uses the same comparison for individual options and the "any" sentinel:
For "any", this requires opts_set == 0xffff. In src/decode-ipv4.h, IPV4_OPT_FLAG_* occupy only bits 1 through 12; their union is 0x1ffe. DecodeIPV4Options in src/decode-ipv4.c sets only those flags. Therefore the condition for "any" is unreachable through normal IPv4 options decoding.
Reproducer and actual result¶
The attached suricata-ipopts-any-reproducer.c compiles the original option table, parser and matcher from the examined tag against minimal packet/context type stubs. Option flags and BIT_U16 are also copied from that tag.
Observed output:
opts_set any rr ts nop eol 0x0000 0 0 0 0 0 0x0008 0 1 0 0 0 0x0010 0 0 1 0 0 0x0004 0 0 0 1 0 0x0002 0 0 0 0 1 0x0018 0 1 1 0 0 0x1ffe 0 1 1 1 1 possible_flags=0x1ffe, tested_subsets=4096, any_matches=0
All 4096 subsets of defined flags produce zero matches for "any". Individual option controls match as expected. The harness asserts these observed results; its successful exit means the bug was reproduced.
Verification scope: source inspection and isolated function execution. A complete Suricata binary was not built or run, and no PCAP replay was executed. The 0x1ffe row is a mask-level check, not a claim that all options fit together in a valid on-wire packet.
Expected behavior and regression coverage¶
For an IPv4 packet with opts_set = IPV4_OPT_FLAG_RR, parsing "any" and calling DetectIpOptsMatch should return 1. It currently returns 0. Parsing "rr" returns 1 for the same packet. With no options, "any" should return 0.
Handle the "any" sentinel separately from the all-required-bits comparison and add regression coverage for packets with and without options. The intended behavior for unrecognized options should also be explicit when choosing between opts_set and opt_cnt.
Source references¶
https://github.com/OISF/suricata/blob/suricata-8.0.7/src/detect-ipopts.c#L117-L120
https://github.com/OISF/suricata/blob/suricata-8.0.7/src/detect-ipopts.c#L176-L187
https://github.com/OISF/suricata/blob/suricata-8.0.7/src/decode-ipv4.h#L116-L132
https://github.com/OISF/suricata/blob/suricata-8.0.7/src/decode-ipv4.c#L296-L468
https://docs.suricata.io/en/suricata-8.0.7/rules/header-keywords.html#ipopts
Related: #6864, a closed issue about false positives for specific options (ssrr versus Stream ID). This report concerns false negatives for the "any" argument.
Files
No data to display