diff options
author | João Valverde <j@v6e.pt> | 2021-10-05 12:13:15 +0100 |
---|---|---|
committer | João Valverde <j@v6e.pt> | 2021-10-05 16:39:41 +0100 |
commit | d45ba348fd12a058e8925bf08827eadc0d3c82b0 (patch) | |
tree | b9cf646a4293f10a579ea12fad8189fac118eac1 | |
parent | f7a2abb4ae20e44b93f47568fdb8e98bbd1ea5a8 (diff) |
dfilter: Strengthen sanity check for range
Allow an entity in the grammar as range body. Perform a stronger
sanity check during semantic analysis everywhere a range is used.
This is both safer (unless we want to allow FIELD bodies only, but
functions are allowed too) and also provides better error messages.
Previously a range of range only compiled on the RHS. Now it can
appear on both sides of a relation.
This fixes a crash with STRING entities similar to #10690 for
UNPARSED.
This also adds back support for slicing functions that was removed
in f3f833ccecce0e8611b2f1990d0fcf81959fcb78 (by accident presumably).
Ping #10690
-rw-r--r-- | epan/dfilter/grammar.lemon | 4 | ||||
-rw-r--r-- | epan/dfilter/semcheck.c | 81 | ||||
-rw-r--r-- | test/suite_dfilter/group_range_method.py | 12 |
3 files changed, 59 insertions, 38 deletions
diff --git a/epan/dfilter/grammar.lemon b/epan/dfilter/grammar.lemon index 85fb9aa029..48516a1a15 100644 --- a/epan/dfilter/grammar.lemon +++ b/epan/dfilter/grammar.lemon @@ -186,9 +186,7 @@ entity(E) ::= CHARCONST(C). { E = C; } entity(E) ::= UNPARSED(U). { E = U; } entity(E) ::= range(R). { E = R; } -range_body(B) ::= FIELD(F). { B = F; } -range_body(B) ::= STRING(S). { B = S; } -range_body(B) ::= range(R). { B = R; } +range_body(B) ::= entity(E). { B = E; } /* Ranges */ range(R) ::= range_body(B) LBRACKET range_node_list(L) RBRACKET. diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c index 86ab74fb16..38d79dfc3a 100644 --- a/epan/dfilter/semcheck.c +++ b/epan/dfilter/semcheck.c @@ -35,6 +35,9 @@ semcheck(dfwork_t *dfw, stnode_t *st_node); static stnode_t* check_param_entity(dfwork_t *dfw, stnode_t *st_node); +static void +check_function(dfwork_t *dfw, stnode_t *st_node); + typedef gboolean (*FtypeCanFunc)(enum ftenum); /* Compares to ftenum_t's and decides if they're @@ -573,7 +576,46 @@ check_drange_node_sanity(gpointer data, gpointer user_data) static void check_drange_sanity(dfwork_t *dfw, stnode_t *st) { + stnode_t *entity1; + header_field_info *hfinfo1; + ftenum_t ftype1; struct check_drange_sanity_args args; + char *s; + + entity1 = sttype_range_entity(st); + if (entity1 && stnode_type_id(entity1) == STTYPE_FIELD) { + hfinfo1 = (header_field_info *)stnode_data(entity1); + ftype1 = hfinfo1->type; + + if (!ftype_can_slice(ftype1)) { + dfilter_fail(dfw, "\"%s\" is a %s and cannot be sliced into a sequence of bytes.", + hfinfo1->abbrev, ftype_pretty_name(ftype1)); + THROW(TypeError); + } + } else if (entity1 && stnode_type_id(entity1) == STTYPE_FUNCTION) { + df_func_def_t *funcdef = sttype_function_funcdef(entity1); + ftype1 = funcdef->retval_ftype; + + if (!ftype_can_slice(ftype1)) { + dfilter_fail(dfw, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", + funcdef->name, ftype_pretty_name(ftype1)); + THROW(TypeError); + } + + check_function(dfw, entity1); + } else if (entity1 && stnode_type_id(entity1) == STTYPE_RANGE) { + /* Should this be rejected instead? */ + check_drange_sanity(dfw, entity1); + } else if (entity1) { + s = stnode_tostr(entity1); + dfilter_fail(dfw, "Range is not supported for entity %s of type %s", + s, stnode_type_name(entity1)); + g_free(s); + THROW(TypeError); + } else { + dfilter_fail(dfw, "Range is not supported, details: " G_STRLOC " entity: NULL"); + THROW(TypeError); + } args.dfw = dfw; args.st = st; @@ -1045,9 +1087,8 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string, { stnode_t *new_st; sttype_id_t type2; - stnode_t *entity1; - header_field_info *hfinfo1, *hfinfo2; - ftenum_t ftype1, ftype2; + header_field_info *hfinfo2; + ftenum_t ftype2; fvalue_t *fvalue; GRegex *pcre; char *s; @@ -1055,40 +1096,10 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string, ws_debug("5 check_relation_LHS_RANGE(%s)", relation_string); - type2 = stnode_type_id(st_arg2); - entity1 = sttype_range_entity(st_arg1); - if (entity1 && stnode_type_id(entity1) == STTYPE_FIELD) { - hfinfo1 = (header_field_info *)stnode_data(entity1); - ftype1 = hfinfo1->type; - - if (!ftype_can_slice(ftype1)) { - dfilter_fail(dfw, "\"%s\" is a %s and cannot be sliced into a sequence of bytes.", - hfinfo1->abbrev, ftype_pretty_name(ftype1)); - THROW(TypeError); - } - } else if (entity1 && stnode_type_id(entity1) == STTYPE_FUNCTION) { - df_func_def_t *funcdef = sttype_function_funcdef(entity1); - ftype1 = funcdef->retval_ftype; - - if (!ftype_can_slice(ftype1)) { - dfilter_fail(dfw, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", - funcdef->name, ftype_pretty_name(ftype1)); - THROW(TypeError); - } - - check_function(dfw, entity1); - - } else if (entity1) { - dfilter_fail(dfw, "Range is not supported for entity %s of type %s", - stnode_token_value(entity1), stnode_type_name(entity1)); - THROW(TypeError); - } else { - dfilter_fail(dfw, "Range is not supported, details: " G_STRLOC " entity: NULL"); - THROW(TypeError); - } - check_drange_sanity(dfw, st_arg1); + type2 = stnode_type_id(st_arg2); + if (type2 == STTYPE_FIELD) { ws_debug("5 check_relation_LHS_RANGE(type2 = STTYPE_FIELD)"); hfinfo2 = (header_field_info*)stnode_data(st_arg2); diff --git a/test/suite_dfilter/group_range_method.py b/test/suite_dfilter/group_range_method.py index 4570171bb3..c3068a6ea0 100644 --- a/test/suite_dfilter/group_range_method.py +++ b/test/suite_dfilter/group_range_method.py @@ -34,3 +34,15 @@ class case_range(unittest.TestCase): def test_slice_2_neg(self, checkDFilterCount): dfilter = "ipx.src.node[3:2] == cc:dd" checkDFilterCount(dfilter, 0) + + def test_slice_string_1(self, checkDFilterFail): + dfilter = "frame == \"00\"[1]" + checkDFilterFail(dfilter, "Range is not supported for entity 00 of type STRING") + + def test_slice_unparsed_1(self, checkDFilterFail): + dfilter = "a == b[1]" + checkDFilterFail(dfilter, "Range is not supported for entity b of type UNPARSED") + + def test_slice_func_1(self, checkDFilterSucceed): + dfilter = "string(ipx.src.node)[3:2] == \"cc:dd\"" + checkDFilterSucceed(dfilter) |