From: Philippe Proulx Date: Sun, 19 Feb 2017 01:04:11 +0000 (-0500) Subject: Filtering: add support for star-only globbing patterns X-Git-Tag: v2.10.0-rc1~10 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=02aca19338c57e5a26d11faedf031b90eaf4899c;p=lttng-modules.git Filtering: add support for star-only globbing patterns This patch adds the support for "full" star-only globbing patterns to be used in filter literal strings. A star-only globbing pattern is a globbing pattern with the star (`*`) being the only special character. This means `?` and character sets (`[abc-k]`) are not supported here. We cannot support them without a strategy to differentiate the globbing pattern because `?` and `[` are not special characters in filter literal strings right now. The eventual strategy to support them would probably look like this: filename =* "?sys*.[ch]" The filter bytecode generator in LTTng-tools's session daemon creates the new FILTER_OP_LOAD_STAR_GLOB_STRING operation when the interpreter should load a star globbing pattern literal string. Even if both "plain", or legacy strings and star globbing pattern strings are literal strings, they do not represent the same thing, that is, the == and != operators act differently. The validation process checks that: 1. There's no binary operator between two FILTER_OP_LOAD_STAR_GLOB_STRING operations. It is illegal to compare two star globbing patterns, as this is not trivial to implement, and completely useless as far as I know. 2. Only the == and != binary operators are allowed between a star globbing pattern and a string. For the special case of star globbing patterns with a star at the end only, the current behaviour is not changed to preserve a maximum of backward compatibility. This is also why the ABI version is changed from 2.2 to 2.3, not to 3.0. == or != operations between REG_STRING and REG_STAR_GLOB_STRING registers is specialized to FILTER_OP_EQ_STAR_GLOB_STRING and FILTER_OP_NE_STAR_GLOB_STRING. Which side is the actual globbing pattern (the one with the REG_STAR_GLOB_STRING type) is checked at execution time. The strutils_star_glob_match() function is used to perform the match operation. See the implementation for more details. Signed-off-by: Philippe Proulx Signed-off-by: Mathieu Desnoyers --- diff --git a/filter-bytecode.h b/filter-bytecode.h index 376c7518..2c14e223 100644 --- a/filter-bytecode.h +++ b/filter-bytecode.h @@ -49,110 +49,120 @@ struct literal_string { } __attribute__((packed)); enum filter_op { - FILTER_OP_UNKNOWN = 0, + FILTER_OP_UNKNOWN = 0, - FILTER_OP_RETURN, + FILTER_OP_RETURN = 1, /* binary */ - FILTER_OP_MUL, - FILTER_OP_DIV, - FILTER_OP_MOD, - FILTER_OP_PLUS, - FILTER_OP_MINUS, - FILTER_OP_RSHIFT, - FILTER_OP_LSHIFT, - FILTER_OP_BIN_AND, - FILTER_OP_BIN_OR, - FILTER_OP_BIN_XOR, + FILTER_OP_MUL = 2, + FILTER_OP_DIV = 3, + FILTER_OP_MOD = 4, + FILTER_OP_PLUS = 5, + FILTER_OP_MINUS = 6, + FILTER_OP_RSHIFT = 7, + FILTER_OP_LSHIFT = 8, + FILTER_OP_BIN_AND = 9, + FILTER_OP_BIN_OR = 10, + FILTER_OP_BIN_XOR = 11, /* binary comparators */ - FILTER_OP_EQ, - FILTER_OP_NE, - FILTER_OP_GT, - FILTER_OP_LT, - FILTER_OP_GE, - FILTER_OP_LE, - - /* string binary comparator */ - FILTER_OP_EQ_STRING, - FILTER_OP_NE_STRING, - FILTER_OP_GT_STRING, - FILTER_OP_LT_STRING, - FILTER_OP_GE_STRING, - FILTER_OP_LE_STRING, + FILTER_OP_EQ = 12, + FILTER_OP_NE = 13, + FILTER_OP_GT = 14, + FILTER_OP_LT = 15, + FILTER_OP_GE = 16, + FILTER_OP_LE = 17, + + /* string binary comparator: apply to */ + FILTER_OP_EQ_STRING = 18, + FILTER_OP_NE_STRING = 19, + FILTER_OP_GT_STRING = 20, + FILTER_OP_LT_STRING = 21, + FILTER_OP_GE_STRING = 22, + FILTER_OP_LE_STRING = 23, /* s64 binary comparator */ - FILTER_OP_EQ_S64, - FILTER_OP_NE_S64, - FILTER_OP_GT_S64, - FILTER_OP_LT_S64, - FILTER_OP_GE_S64, - FILTER_OP_LE_S64, + FILTER_OP_EQ_S64 = 24, + FILTER_OP_NE_S64 = 25, + FILTER_OP_GT_S64 = 26, + FILTER_OP_LT_S64 = 27, + FILTER_OP_GE_S64 = 28, + FILTER_OP_LE_S64 = 29, /* double binary comparator */ - FILTER_OP_EQ_DOUBLE, - FILTER_OP_NE_DOUBLE, - FILTER_OP_GT_DOUBLE, - FILTER_OP_LT_DOUBLE, - FILTER_OP_GE_DOUBLE, - FILTER_OP_LE_DOUBLE, + FILTER_OP_EQ_DOUBLE = 30, + FILTER_OP_NE_DOUBLE = 31, + FILTER_OP_GT_DOUBLE = 32, + FILTER_OP_LT_DOUBLE = 33, + FILTER_OP_GE_DOUBLE = 34, + FILTER_OP_LE_DOUBLE = 35, /* Mixed S64-double binary comparators */ - FILTER_OP_EQ_DOUBLE_S64, - FILTER_OP_NE_DOUBLE_S64, - FILTER_OP_GT_DOUBLE_S64, - FILTER_OP_LT_DOUBLE_S64, - FILTER_OP_GE_DOUBLE_S64, - FILTER_OP_LE_DOUBLE_S64, - - FILTER_OP_EQ_S64_DOUBLE, - FILTER_OP_NE_S64_DOUBLE, - FILTER_OP_GT_S64_DOUBLE, - FILTER_OP_LT_S64_DOUBLE, - FILTER_OP_GE_S64_DOUBLE, - FILTER_OP_LE_S64_DOUBLE, + FILTER_OP_EQ_DOUBLE_S64 = 36, + FILTER_OP_NE_DOUBLE_S64 = 37, + FILTER_OP_GT_DOUBLE_S64 = 38, + FILTER_OP_LT_DOUBLE_S64 = 39, + FILTER_OP_GE_DOUBLE_S64 = 40, + FILTER_OP_LE_DOUBLE_S64 = 41, + + FILTER_OP_EQ_S64_DOUBLE = 42, + FILTER_OP_NE_S64_DOUBLE = 43, + FILTER_OP_GT_S64_DOUBLE = 44, + FILTER_OP_LT_S64_DOUBLE = 45, + FILTER_OP_GE_S64_DOUBLE = 46, + FILTER_OP_LE_S64_DOUBLE = 47, /* unary */ - FILTER_OP_UNARY_PLUS, - FILTER_OP_UNARY_MINUS, - FILTER_OP_UNARY_NOT, - FILTER_OP_UNARY_PLUS_S64, - FILTER_OP_UNARY_MINUS_S64, - FILTER_OP_UNARY_NOT_S64, - FILTER_OP_UNARY_PLUS_DOUBLE, - FILTER_OP_UNARY_MINUS_DOUBLE, - FILTER_OP_UNARY_NOT_DOUBLE, + FILTER_OP_UNARY_PLUS = 48, + FILTER_OP_UNARY_MINUS = 49, + FILTER_OP_UNARY_NOT = 50, + FILTER_OP_UNARY_PLUS_S64 = 51, + FILTER_OP_UNARY_MINUS_S64 = 52, + FILTER_OP_UNARY_NOT_S64 = 53, + FILTER_OP_UNARY_PLUS_DOUBLE = 54, + FILTER_OP_UNARY_MINUS_DOUBLE = 55, + FILTER_OP_UNARY_NOT_DOUBLE = 56, /* logical */ - FILTER_OP_AND, - FILTER_OP_OR, + FILTER_OP_AND = 57, + FILTER_OP_OR = 58, /* load field ref */ - FILTER_OP_LOAD_FIELD_REF, - FILTER_OP_LOAD_FIELD_REF_STRING, - FILTER_OP_LOAD_FIELD_REF_SEQUENCE, - FILTER_OP_LOAD_FIELD_REF_S64, - FILTER_OP_LOAD_FIELD_REF_DOUBLE, + FILTER_OP_LOAD_FIELD_REF = 59, + FILTER_OP_LOAD_FIELD_REF_STRING = 60, + FILTER_OP_LOAD_FIELD_REF_SEQUENCE = 61, + FILTER_OP_LOAD_FIELD_REF_S64 = 62, + FILTER_OP_LOAD_FIELD_REF_DOUBLE = 63, /* load immediate from operand */ - FILTER_OP_LOAD_STRING, - FILTER_OP_LOAD_S64, - FILTER_OP_LOAD_DOUBLE, + FILTER_OP_LOAD_STRING = 64, + FILTER_OP_LOAD_S64 = 65, + FILTER_OP_LOAD_DOUBLE = 66, /* cast */ - FILTER_OP_CAST_TO_S64, - FILTER_OP_CAST_DOUBLE_TO_S64, - FILTER_OP_CAST_NOP, + FILTER_OP_CAST_TO_S64 = 67, + FILTER_OP_CAST_DOUBLE_TO_S64 = 68, + FILTER_OP_CAST_NOP = 69, /* get context ref */ - FILTER_OP_GET_CONTEXT_REF, - FILTER_OP_GET_CONTEXT_REF_STRING, - FILTER_OP_GET_CONTEXT_REF_S64, - FILTER_OP_GET_CONTEXT_REF_DOUBLE, + FILTER_OP_GET_CONTEXT_REF = 70, + FILTER_OP_GET_CONTEXT_REF_STRING = 71, + FILTER_OP_GET_CONTEXT_REF_S64 = 72, + FILTER_OP_GET_CONTEXT_REF_DOUBLE = 73, /* load userspace field ref */ - FILTER_OP_LOAD_FIELD_REF_USER_STRING, - FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE, + FILTER_OP_LOAD_FIELD_REF_USER_STRING = 74, + FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE = 75, + + /* + * load immediate star globbing pattern (literal string) + * from immediate + */ + FILTER_OP_LOAD_STAR_GLOB_STRING = 76, + + /* globbing pattern binary operator: apply to */ + FILTER_OP_EQ_STAR_GLOB_STRING = 77, + FILTER_OP_NE_STAR_GLOB_STRING = 78, NR_FILTER_OPS, }; diff --git a/lttng-filter-interpreter.c b/lttng-filter-interpreter.c index 761926f7..a09b0417 100644 --- a/lttng-filter-interpreter.c +++ b/lttng-filter-interpreter.c @@ -28,6 +28,7 @@ #include #include +#include LTTNG_STACK_FRAME_NON_STANDARD(lttng_filter_interpret_bytecode); @@ -85,6 +86,49 @@ int parse_char(struct estack_entry *reg, char *c, size_t *offset) } } +static +char get_char_at_cb(size_t at, void *data) +{ + return get_char(data, at); +} + +static +int stack_star_glob_match(struct estack *stack, int top, const char *cmp_type) +{ + bool has_user = false; + mm_segment_t old_fs; + int result; + struct estack_entry *pattern_reg; + struct estack_entry *candidate_reg; + + if (estack_bx(stack, top)->u.s.user + || estack_ax(stack, top)->u.s.user) { + has_user = true; + old_fs = get_fs(); + set_fs(KERNEL_DS); + pagefault_disable(); + } + + /* Find out which side is the pattern vs. the candidate. */ + if (estack_ax(stack, top)->u.s.literal_type == ESTACK_STRING_LITERAL_TYPE_STAR_GLOB) { + pattern_reg = estack_ax(stack, top); + candidate_reg = estack_bx(stack, top); + } else { + pattern_reg = estack_bx(stack, top); + candidate_reg = estack_ax(stack, top); + } + + /* Perform the match operation. */ + result = !strutils_star_glob_match_char_cb(get_char_at_cb, + pattern_reg, get_char_at_cb, candidate_reg); + if (has_user) { + pagefault_enable(); + set_fs(old_fs); + } + + return result; +} + static int stack_strcmp(struct estack *stack, int top, const char *cmp_type) { @@ -113,7 +157,8 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) diff = 0; break; } else { - if (estack_ax(stack, top)->u.s.literal) { + if (estack_ax(stack, top)->u.s.literal_type == + ESTACK_STRING_LITERAL_TYPE_PLAIN) { ret = parse_char(estack_ax(stack, top), &char_ax, &offset_ax); if (ret == -1) { @@ -126,7 +171,8 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) } } if (unlikely(char_ax == '\0')) { - if (estack_bx(stack, top)->u.s.literal) { + if (estack_bx(stack, top)->u.s.literal_type == + ESTACK_STRING_LITERAL_TYPE_PLAIN) { ret = parse_char(estack_bx(stack, top), &char_bx, &offset_bx); if (ret == -1) { @@ -137,7 +183,8 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) diff = 1; break; } - if (estack_bx(stack, top)->u.s.literal) { + if (estack_bx(stack, top)->u.s.literal_type == + ESTACK_STRING_LITERAL_TYPE_PLAIN) { ret = parse_char(estack_bx(stack, top), &char_bx, &offset_bx); if (ret == -1) { @@ -148,7 +195,8 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) } /* else compare both char */ } - if (estack_ax(stack, top)->u.s.literal) { + if (estack_ax(stack, top)->u.s.literal_type == + ESTACK_STRING_LITERAL_TYPE_PLAIN) { ret = parse_char(estack_ax(stack, top), &char_ax, &offset_ax); if (ret == -1) { @@ -288,6 +336,10 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, [ FILTER_OP_GE_STRING ] = &&LABEL_FILTER_OP_GE_STRING, [ FILTER_OP_LE_STRING ] = &&LABEL_FILTER_OP_LE_STRING, + /* globbing pattern binary comparator */ + [ FILTER_OP_EQ_STAR_GLOB_STRING ] = &&LABEL_FILTER_OP_EQ_STAR_GLOB_STRING, + [ FILTER_OP_NE_STAR_GLOB_STRING ] = &&LABEL_FILTER_OP_NE_STAR_GLOB_STRING, + /* s64 binary comparator */ [ FILTER_OP_EQ_S64 ] = &&LABEL_FILTER_OP_EQ_S64, [ FILTER_OP_NE_S64 ] = &&LABEL_FILTER_OP_NE_S64, @@ -343,6 +395,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, /* load from immediate operand */ [ FILTER_OP_LOAD_STRING ] = &&LABEL_FILTER_OP_LOAD_STRING, + [ FILTER_OP_LOAD_STAR_GLOB_STRING ] = &&LABEL_FILTER_OP_LOAD_STAR_GLOB_STRING, [ FILTER_OP_LOAD_S64 ] = &&LABEL_FILTER_OP_LOAD_S64, [ FILTER_OP_LOAD_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_DOUBLE, @@ -470,6 +523,27 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, PO; } + OP(FILTER_OP_EQ_STAR_GLOB_STRING): + { + int res; + + res = (stack_star_glob_match(stack, top, "==") == 0); + estack_pop(stack, top, ax, bx); + estack_ax_v = res; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_NE_STAR_GLOB_STRING): + { + int res; + + res = (stack_star_glob_match(stack, top, "!=") != 0); + estack_pop(stack, top, ax, bx); + estack_ax_v = res; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_EQ_S64): { int res; @@ -653,7 +727,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; } estack_ax(stack, top)->u.s.seq_len = UINT_MAX; - estack_ax(stack, top)->u.s.literal = 0; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax(stack, top)->u.s.user = 0; dbg_printk("ref load string %s\n", estack_ax(stack, top)->u.s.str); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); @@ -678,7 +753,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, ret = -EINVAL; goto end; } - estack_ax(stack, top)->u.s.literal = 0; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax(stack, top)->u.s.user = 0; next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; @@ -715,7 +791,23 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, estack_push(stack, top, ax, bx); estack_ax(stack, top)->u.s.str = insn->data; estack_ax(stack, top)->u.s.seq_len = UINT_MAX; - estack_ax(stack, top)->u.s.literal = 1; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_PLAIN; + estack_ax(stack, top)->u.s.user = 0; + next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; + PO; + } + + OP(FILTER_OP_LOAD_STAR_GLOB_STRING): + { + struct load_op *insn = (struct load_op *) pc; + + dbg_printk("load globbing pattern %s\n", insn->data); + estack_push(stack, top, ax, bx); + estack_ax(stack, top)->u.s.str = insn->data; + estack_ax(stack, top)->u.s.seq_len = UINT_MAX; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_STAR_GLOB; estack_ax(stack, top)->u.s.user = 0; next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; PO; @@ -779,7 +871,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; } estack_ax(stack, top)->u.s.seq_len = UINT_MAX; - estack_ax(stack, top)->u.s.literal = 0; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax(stack, top)->u.s.user = 0; dbg_printk("ref get context string %s\n", estack_ax(stack, top)->u.s.str); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); @@ -828,7 +921,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; } estack_ax(stack, top)->u.s.seq_len = UINT_MAX; - estack_ax(stack, top)->u.s.literal = 0; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax(stack, top)->u.s.user = 1; dbg_printk("ref load string %s\n", estack_ax(stack, top)->u.s.str); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); @@ -853,7 +947,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, ret = -EINVAL; goto end; } - estack_ax(stack, top)->u.s.literal = 0; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax(stack, top)->u.s.user = 1; next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; diff --git a/lttng-filter-specialize.c b/lttng-filter-specialize.c index 66768955..318d051a 100644 --- a/lttng-filter-specialize.c +++ b/lttng-filter-specialize.c @@ -77,7 +77,13 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) goto end; case REG_STRING: - insn->op = FILTER_OP_EQ_STRING; + if (vstack_bx(stack)->type == REG_STAR_GLOB_STRING) + insn->op = FILTER_OP_EQ_STAR_GLOB_STRING; + else + insn->op = FILTER_OP_EQ_STRING; + break; + case REG_STAR_GLOB_STRING: + insn->op = FILTER_OP_EQ_STAR_GLOB_STRING; break; case REG_S64: if (vstack_bx(stack)->type == REG_S64) @@ -113,7 +119,13 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) goto end; case REG_STRING: - insn->op = FILTER_OP_NE_STRING; + if (vstack_bx(stack)->type == REG_STAR_GLOB_STRING) + insn->op = FILTER_OP_NE_STAR_GLOB_STRING; + else + insn->op = FILTER_OP_NE_STRING; + break; + case REG_STAR_GLOB_STRING: + insn->op = FILTER_OP_NE_STAR_GLOB_STRING; break; case REG_S64: if (vstack_bx(stack)->type == REG_S64) @@ -148,6 +160,10 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) ret = -EINVAL; goto end; + case REG_STAR_GLOB_STRING: + printk(KERN_WARNING "invalid register type for > binary operator\n"); + ret = -EINVAL; + goto end; case REG_STRING: insn->op = FILTER_OP_GT_STRING; break; @@ -184,6 +200,10 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) ret = -EINVAL; goto end; + case REG_STAR_GLOB_STRING: + printk(KERN_WARNING "invalid register type for < binary operator\n"); + ret = -EINVAL; + goto end; case REG_STRING: insn->op = FILTER_OP_LT_STRING; break; @@ -220,6 +240,10 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) ret = -EINVAL; goto end; + case REG_STAR_GLOB_STRING: + printk(KERN_WARNING "invalid register type for >= binary operator\n"); + ret = -EINVAL; + goto end; case REG_STRING: insn->op = FILTER_OP_GE_STRING; break; @@ -255,6 +279,10 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) ret = -EINVAL; goto end; + case REG_STAR_GLOB_STRING: + printk(KERN_WARNING "invalid register type for <= binary operator\n"); + ret = -EINVAL; + goto end; case REG_STRING: insn->op = FILTER_OP_LE_STRING; break; @@ -282,6 +310,8 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) case FILTER_OP_LT_STRING: case FILTER_OP_GE_STRING: case FILTER_OP_LE_STRING: + case FILTER_OP_EQ_STAR_GLOB_STRING: + case FILTER_OP_NE_STAR_GLOB_STRING: case FILTER_OP_EQ_S64: case FILTER_OP_NE_S64: case FILTER_OP_GT_S64: @@ -475,6 +505,19 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) break; } + case FILTER_OP_LOAD_STAR_GLOB_STRING: + { + struct load_op *insn = (struct load_op *) pc; + + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_STAR_GLOB_STRING; + next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; + break; + } + case FILTER_OP_LOAD_S64: { if (vstack_push(stack)) { @@ -511,6 +554,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) goto end; case REG_STRING: + case REG_STAR_GLOB_STRING: printk(KERN_WARNING "Cast op can only be applied to numeric or floating point registers\n"); ret = -EINVAL; goto end; diff --git a/lttng-filter-validator.c b/lttng-filter-validator.c index 123a1308..1c30a529 100644 --- a/lttng-filter-validator.c +++ b/lttng-filter-validator.c @@ -118,7 +118,8 @@ int merge_point_add_check(struct mp_table *mp_table, unsigned long target_pc, * Binary comparators use top of stack and top of stack -1. */ static -int bin_op_compare_check(struct vstack *stack, const char *str) +int bin_op_compare_check(struct vstack *stack, const filter_opcode_t opcode, + const char *str) { if (unlikely(!vstack_ax(stack) || !vstack_bx(stack))) goto error_unknown; @@ -136,6 +137,27 @@ int bin_op_compare_check(struct vstack *stack, const char *str) case REG_STRING: break; + case REG_STAR_GLOB_STRING: + if (opcode != FILTER_OP_EQ && opcode != FILTER_OP_NE) { + goto error_mismatch; + } + break; + case REG_S64: + goto error_mismatch; + } + break; + case REG_STAR_GLOB_STRING: + switch (vstack_bx(stack)->type) { + default: + case REG_DOUBLE: + goto error_unknown; + + case REG_STRING: + if (opcode != FILTER_OP_EQ && opcode != FILTER_OP_NE) { + goto error_mismatch; + } + break; + case REG_STAR_GLOB_STRING: case REG_S64: goto error_mismatch; } @@ -147,6 +169,7 @@ int bin_op_compare_check(struct vstack *stack, const char *str) goto error_unknown; case REG_STRING: + case REG_STAR_GLOB_STRING: goto error_mismatch; case REG_S64: @@ -249,6 +272,8 @@ int bytecode_validate_overflow(struct bytecode_runtime *bytecode, case FILTER_OP_LT_STRING: case FILTER_OP_GE_STRING: case FILTER_OP_LE_STRING: + case FILTER_OP_EQ_STAR_GLOB_STRING: + case FILTER_OP_NE_STAR_GLOB_STRING: case FILTER_OP_EQ_S64: case FILTER_OP_NE_S64: case FILTER_OP_GT_S64: @@ -320,6 +345,7 @@ int bytecode_validate_overflow(struct bytecode_runtime *bytecode, /* load from immediate operand */ case FILTER_OP_LOAD_STRING: + case FILTER_OP_LOAD_STAR_GLOB_STRING: { struct load_op *insn = (struct load_op *) pc; uint32_t str_len, maxlen; @@ -395,8 +421,9 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, char *pc) { int ret = 0; + const filter_opcode_t opcode = *(filter_opcode_t *) pc; - switch (*(filter_opcode_t *) pc) { + switch (opcode) { case FILTER_OP_UNKNOWN: default: { @@ -457,42 +484,42 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, case FILTER_OP_EQ: { - ret = bin_op_compare_check(stack, "=="); + ret = bin_op_compare_check(stack, opcode, "=="); if (ret) goto end; break; } case FILTER_OP_NE: { - ret = bin_op_compare_check(stack, "!="); + ret = bin_op_compare_check(stack, opcode, "!="); if (ret) goto end; break; } case FILTER_OP_GT: { - ret = bin_op_compare_check(stack, ">"); + ret = bin_op_compare_check(stack, opcode, ">"); if (ret) goto end; break; } case FILTER_OP_LT: { - ret = bin_op_compare_check(stack, "<"); + ret = bin_op_compare_check(stack, opcode, "<"); if (ret) goto end; break; } case FILTER_OP_GE: { - ret = bin_op_compare_check(stack, ">="); + ret = bin_op_compare_check(stack, opcode, ">="); if (ret) goto end; break; } case FILTER_OP_LE: { - ret = bin_op_compare_check(stack, "<="); + ret = bin_op_compare_check(stack, opcode, "<="); if (ret) goto end; break; @@ -519,6 +546,24 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, break; } + + case FILTER_OP_EQ_STAR_GLOB_STRING: + case FILTER_OP_NE_STAR_GLOB_STRING: + { + if (!vstack_ax(stack) || !vstack_bx(stack)) { + printk(KERN_WARNING "Empty stack\n"); + ret = -EINVAL; + goto end; + } + if (vstack_ax(stack)->type != REG_STAR_GLOB_STRING + && vstack_bx(stack)->type != REG_STAR_GLOB_STRING) { + printk(KERN_WARNING "Unexpected register type for globbing pattern comparator\n"); + ret = -EINVAL; + goto end; + } + break; + } + case FILTER_OP_EQ_S64: case FILTER_OP_NE_S64: case FILTER_OP_GT_S64: @@ -558,6 +603,7 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, goto end; case REG_STRING: + case REG_STAR_GLOB_STRING: printk(KERN_WARNING "Unary op can only be applied to numeric or floating point registers\n"); ret = -EINVAL; goto end; @@ -642,6 +688,7 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, /* load from immediate operand */ case FILTER_OP_LOAD_STRING: + case FILTER_OP_LOAD_STAR_GLOB_STRING: { break; } @@ -668,6 +715,7 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, goto end; case REG_STRING: + case REG_STAR_GLOB_STRING: printk(KERN_WARNING "Cast op can only be applied to numeric or floating point registers\n"); ret = -EINVAL; goto end; @@ -860,6 +908,8 @@ int exec_insn(struct bytecode_runtime *bytecode, case FILTER_OP_LT_STRING: case FILTER_OP_GE_STRING: case FILTER_OP_LE_STRING: + case FILTER_OP_EQ_STAR_GLOB_STRING: + case FILTER_OP_NE_STAR_GLOB_STRING: case FILTER_OP_EQ_S64: case FILTER_OP_NE_S64: case FILTER_OP_GT_S64: @@ -979,6 +1029,19 @@ int exec_insn(struct bytecode_runtime *bytecode, break; } + case FILTER_OP_LOAD_STAR_GLOB_STRING: + { + struct load_op *insn = (struct load_op *) pc; + + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_STAR_GLOB_STRING; + next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; + break; + } + case FILTER_OP_LOAD_S64: { if (vstack_push(stack)) { diff --git a/lttng-filter.h b/lttng-filter.h index 6ce78ac4..01bafa05 100644 --- a/lttng-filter.h +++ b/lttng-filter.h @@ -61,6 +61,7 @@ enum entry_type { REG_S64, REG_DOUBLE, REG_STRING, + REG_STAR_GLOB_STRING, REG_TYPE_UNKNOWN, }; @@ -119,6 +120,12 @@ int vstack_pop(struct vstack *stack) } /* Execution stack */ +enum estack_string_literal_type { + ESTACK_STRING_LITERAL_TYPE_NONE, + ESTACK_STRING_LITERAL_TYPE_PLAIN, + ESTACK_STRING_LITERAL_TYPE_STAR_GLOB, +}; + struct estack_entry { union { int64_t v; @@ -127,7 +134,7 @@ struct estack_entry { const char *str; const char __user *user_str; size_t seq_len; - int literal; /* is string literal ? */ + enum estack_string_literal_type literal_type; int user; /* is string from userspace ? */ } s; } u;