Project

General

Profile

Actions

Bug #9423

open
LZ

detect/ipopts: ipopts:any never matches because 0xffff is compared as a required mask

Bug #9423: detect/ipopts: ipopts:any never matches because 0xffff is compared as a required mask

Added by Leonid Zaytsev 1 day ago.

Status:
New
Priority:
Normal
Assignee:
-
Target version:
Affected Versions:
Effort:
Difficulty:
Label:
C

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:

alert ip any any -> any any (msg:"IPv4 options present"; ipopts:any; sid:1000001; rev:1;)

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:

return (p->l3.vars.ip4.opts_set & de->ipopt) == de->ipopt;

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.

cc -std=c11 -O2 suricata-ipopts-any-reproducer.c -o ipopts-repro
./ipopts-repro

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

suricata-ipopts-any-reproducer.c (5.73 KB) suricata-ipopts-any-reproducer.c Leonid Zaytsev, 11/13/2026 10:32 AM

No data to display

Actions

Also available in: PDF Atom