Dumping and restoring a tc filter with an FSM text ematch can silently change which packets it matches, or fail to restore it with EINVAL. This happens when userspace reuses the pattern returned by RTM_GETTFILTER to configure another filter. Dumping alone does not change the live filter. fsm_init() replaces each public token type with an internal character-class mask, and fsm_get_pattern() returns that converted array. For example, TS_FSM_DIGIT (2) becomes the _D mask (4). Restoring the exported pattern interprets 4 as TS_FSM_PRINT. With a DIGIT/MULTI pattern, a rule that matched the UDP payload "7777" but rejected "AAAA" starts matching both after restoration. Other exported masks exceed TS_FSM_TYPE_MAX and are rejected with EINVAL. Keep the public token types in the configuration and look up their masks in match_token(). This preserves the exported representation without adding another pattern allocation. Initialization still validates every type before it can be used to index token_map. The extra lookup during character-class matching avoids storing a second copy of the pattern. I identified this issue. OpenAI Codex helped confirm it and drafted the fix and changelog. I reviewed the fix, built it and verified that the tests passed. Fixes: 6408f79cce40 ("[LIB]: Naive finite state machine based textsearch") Cc: stable@vger.kernel.org Signed-off-by: Zhiqi Zhang --- Changes in v2: describe the tc impact, split out the KUnit tests and add stable. The production code change is unchanged from v1. Validation: updated KUnit tests change from 2/15 to 15/15 passing on ARM64 GCC; ARM32 GCC and ARM64 Clang also pass. An isolated QEMU rtnetlink/UDP test demonstrates altered packet matching and EINVAL restoration before the fix, with both corrected afterwards. See the cover letter for details. An ARM64 userspace microbenchmark of the extracted matcher measured median paired slowdowns of about 1-5% for tested long character-class scans and 13% for a one-byte rejection case with appreciable variability. This is not a measurement of in-kernel or packet throughput. lib/ts_fsm.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/ts_fsm.c b/lib/ts_fsm.c index 053615f4f..8725ea6f0 100644 --- a/lib/ts_fsm.c +++ b/lib/ts_fsm.c @@ -126,7 +126,7 @@ _W|_L, _W|_L, _W|_L, _W|_L}; /* 252-255 */ static inline int match_token(struct ts_fsm_token *t, u8 d) { if (t->type) - return (token_lookup_tbl[d] & t->type) != 0; + return (token_lookup_tbl[d] & token_map[t->type]) != 0; else return t->value == d; } @@ -288,11 +288,6 @@ static struct ts_config *fsm_init(const void *pattern, unsigned int len, fsm->ntokens = ntokens; memcpy(fsm->tokens, pattern, len); - for (i = 0; i < fsm->ntokens; i++) { - struct ts_fsm_token *t = &fsm->tokens[i]; - t->type = token_map[t->type]; - } - return conf; errout: -- 2.54.0 (Apple Git-157)