Filter: cleanup macros
[lttng-ust.git] / liblttng-ust / lttng-filter.c
index db4d107a63df629f07af9c3b2cf6f82858cd92bc..fa306f0760ac64d62f6bce5d67539e2413f68bd8 100644 (file)
@@ -275,20 +275,20 @@ int lttng_filter_false(void *filter_data,
  * Fallback for compilers that do not support taking address of labels.
  */
 
-#define START_OP       \
-       start_pc = &bytecode->data[0]; \
-       for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; \
-                       pc = next_pc) { \
-               dbg_printf("Executing op %s (%u)\n", \
+#define START_OP                                                       \
+       start_pc = &bytecode->data[0];                                  \
+       for (pc = next_pc = start_pc; pc - start_pc < bytecode->len;    \
+                       pc = next_pc) {                                 \
+               dbg_printf("Executing op %s (%u)\n",                    \
                        print_op((unsigned int) *(filter_opcode_t *) pc), \
-                       (unsigned int) *(filter_opcode_t *) pc); \
-               switch (*(filter_opcode_t *) pc) {
+                       (unsigned int) *(filter_opcode_t *) pc);        \
+               switch (*(filter_opcode_t *) pc)        {
 
 #define OP(name)       case name
 
 #define PO             break
 
-#define END_OP         } \
+#define END_OP         }                                               \
        }
 
 #else
@@ -297,18 +297,18 @@ int lttng_filter_false(void *filter_data,
  * Dispatch-table based interpreter.
  */
 
-#define START_OP                                       \
-       start_pc = &bytecode->data[0];                  \
-       pc = next_pc = start_pc;                        \
-       if (unlikely(pc - start_pc >= bytecode->len))   \
-               goto end;                               \
+#define START_OP                                                       \
+       start_pc = &bytecode->data[0];                                  \
+       pc = next_pc = start_pc;                                        \
+       if (unlikely(pc - start_pc >= bytecode->len))                   \
+               goto end;                                               \
        goto *dispatch[*(filter_opcode_t *) pc];
 
-#define OP(name)                                       \
+#define OP(name)                                                       \
 LABEL_##name
 
-#define PO                                             \
-               pc = next_pc;                           \
+#define PO                                                             \
+               pc = next_pc;                                           \
                goto *dispatch[*(filter_opcode_t *) pc];
 
 #define END_OP
@@ -696,6 +696,11 @@ int lttng_filter_interpret_bytecode(void *filter_data,
                                ref->offset);
                        reg[insn->reg].str =
                                *(const char * const *) &filter_stack_data[ref->offset];
+                       if (unlikely(!reg[insn->reg].str)) {
+                               dbg_printf("Filter warning: loading a NULL string.\n");
+                               ret = -EINVAL;
+                               goto end;
+                       }
                        reg[insn->reg].type = REG_STRING;
                        reg[insn->reg].seq_len = UINT_MAX;
                        reg[insn->reg].literal = 0;
@@ -716,6 +721,11 @@ int lttng_filter_interpret_bytecode(void *filter_data,
                        reg[insn->reg].str =
                                *(const char **) (&filter_stack_data[ref->offset
                                                                + sizeof(unsigned long)]);
+                       if (unlikely(!reg[insn->reg].str)) {
+                               dbg_printf("Filter warning: loading a NULL sequence.\n");
+                               ret = -EINVAL;
+                               goto end;
+                       }
                        reg[insn->reg].type = REG_STRING;
                        reg[insn->reg].literal = 0;
                        next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
@@ -871,6 +881,186 @@ error_mismatch:
        return -EINVAL;
 }
 
+/*
+ * Validate bytecode range overflow within the validation pass.
+ * Called for each instruction encountered.
+ */
+static
+int bytecode_validate_overflow(struct bytecode_runtime *bytecode,
+                       void *start_pc, void *pc)
+{
+       int ret = 0;
+
+       switch (*(filter_opcode_t *) pc) {
+       case FILTER_OP_UNKNOWN:
+       default:
+       {
+               ERR("unknown bytecode op %u\n",
+                       (unsigned int) *(filter_opcode_t *) pc);
+               ret = -EINVAL;
+               break;
+       }
+
+       case FILTER_OP_RETURN:
+       {
+               if (unlikely(pc + sizeof(struct return_op)
+                               > start_pc + bytecode->len)) {
+                       ret = -EINVAL;
+               }
+               break;
+       }
+
+       /* binary */
+       case FILTER_OP_MUL:
+       case FILTER_OP_DIV:
+       case FILTER_OP_MOD:
+       case FILTER_OP_PLUS:
+       case FILTER_OP_MINUS:
+       case FILTER_OP_RSHIFT:
+       case FILTER_OP_LSHIFT:
+       case FILTER_OP_BIN_AND:
+       case FILTER_OP_BIN_OR:
+       case FILTER_OP_BIN_XOR:
+       {
+               ERR("unsupported bytecode op %u\n",
+                       (unsigned int) *(filter_opcode_t *) pc);
+               ret = -EINVAL;
+               break;
+       }
+
+       case FILTER_OP_EQ:
+       case FILTER_OP_NE:
+       case FILTER_OP_GT:
+       case FILTER_OP_LT:
+       case FILTER_OP_GE:
+       case FILTER_OP_LE:
+       case FILTER_OP_EQ_STRING:
+       case FILTER_OP_NE_STRING:
+       case FILTER_OP_GT_STRING:
+       case FILTER_OP_LT_STRING:
+       case FILTER_OP_GE_STRING:
+       case FILTER_OP_LE_STRING:
+       case FILTER_OP_EQ_S64:
+       case FILTER_OP_NE_S64:
+       case FILTER_OP_GT_S64:
+       case FILTER_OP_LT_S64:
+       case FILTER_OP_GE_S64:
+       case FILTER_OP_LE_S64:
+       case FILTER_OP_EQ_DOUBLE:
+       case FILTER_OP_NE_DOUBLE:
+       case FILTER_OP_GT_DOUBLE:
+       case FILTER_OP_LT_DOUBLE:
+       case FILTER_OP_GE_DOUBLE:
+       case FILTER_OP_LE_DOUBLE:
+       {
+               if (unlikely(pc + sizeof(struct binary_op)
+                               > start_pc + bytecode->len)) {
+                       ret = -EINVAL;
+               }
+               break;
+       }
+
+       /* unary */
+       case FILTER_OP_UNARY_PLUS:
+       case FILTER_OP_UNARY_MINUS:
+       case FILTER_OP_UNARY_NOT:
+       case FILTER_OP_UNARY_PLUS_S64:
+       case FILTER_OP_UNARY_MINUS_S64:
+       case FILTER_OP_UNARY_NOT_S64:
+       case FILTER_OP_UNARY_PLUS_DOUBLE:
+       case FILTER_OP_UNARY_MINUS_DOUBLE:
+       case FILTER_OP_UNARY_NOT_DOUBLE:
+       {
+               if (unlikely(pc + sizeof(struct unary_op)
+                               > start_pc + bytecode->len)) {
+                       ret = -EINVAL;
+               }
+               break;
+       }
+
+       /* logical */
+       case FILTER_OP_AND:
+       case FILTER_OP_OR:
+       {
+               if (unlikely(pc + sizeof(struct logical_op)
+                               > start_pc + bytecode->len)) {
+                       ret = -EINVAL;
+               }
+               break;
+       }
+
+       /* load */
+       case FILTER_OP_LOAD_FIELD_REF:
+       {
+               ERR("Unknown field ref type\n");
+               ret = -EINVAL;
+               break;
+       }
+       case FILTER_OP_LOAD_FIELD_REF_STRING:
+       case FILTER_OP_LOAD_FIELD_REF_SEQUENCE:
+       case FILTER_OP_LOAD_FIELD_REF_S64:
+       case FILTER_OP_LOAD_FIELD_REF_DOUBLE:
+       {
+               if (unlikely(pc + sizeof(struct load_op) + sizeof(struct field_ref)
+                               > start_pc + bytecode->len)) {
+                       ret = -EINVAL;
+               }
+               break;
+       }
+
+       case FILTER_OP_LOAD_STRING:
+       {
+               struct load_op *insn = (struct load_op *) pc;
+               uint32_t str_len, maxlen;
+
+               if (unlikely(pc + sizeof(struct load_op)
+                               > start_pc + bytecode->len)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               maxlen = start_pc + bytecode->len - pc - sizeof(struct load_op);
+               str_len = strnlen(insn->data, maxlen);
+               if (unlikely(str_len >= maxlen)) {
+                       /* Final '\0' not found within range */
+                       ret = -EINVAL;
+               }
+               break;
+       }
+
+       case FILTER_OP_LOAD_S64:
+       {
+               if (unlikely(pc + sizeof(struct load_op) + sizeof(struct literal_numeric)
+                               > start_pc + bytecode->len)) {
+                       ret = -EINVAL;
+               }
+               break;
+       }
+
+       case FILTER_OP_LOAD_DOUBLE:
+       {
+               if (unlikely(pc + sizeof(struct load_op) + sizeof(struct literal_double)
+                               > start_pc + bytecode->len)) {
+                       ret = -EINVAL;
+               }
+               break;
+       }
+
+       case FILTER_OP_CAST_TO_S64:
+       case FILTER_OP_CAST_DOUBLE_TO_S64:
+       case FILTER_OP_CAST_NOP:
+       {
+               if (unlikely(pc + sizeof(struct cast_op)
+                               > start_pc + bytecode->len)) {
+                       ret = -EINVAL;
+               }
+               break;
+       }
+       }
+
+       return ret;
+}
+
 static
 int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode)
 {
@@ -887,7 +1077,7 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode)
        start_pc = &bytecode->data[0];
        for (pc = next_pc = start_pc; pc - start_pc < bytecode->len;
                        pc = next_pc) {
-               if (unlikely(pc >= start_pc + bytecode->len)) {
+               if (bytecode_validate_overflow(bytecode, start_pc, pc) != 0) {
                        ERR("filter bytecode overflow\n");
                        ret = -EINVAL;
                        goto end;
This page took 0.026368 seconds and 4 git commands to generate.