X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=lttng-filter-interpreter.c;h=6e5a5139e3dfd285fe0500c2558b8c1982fb49ba;hb=00b42dbf832993005036d0bc28aef9eb2171f539;hp=5bf0bd6074719ef59cf5dc8a2fe57f4cc0f5e7e7;hpb=e16c054bb621df50a1710dcd9d1d613f13ef52d2;p=lttng-modules.git diff --git a/lttng-filter-interpreter.c b/lttng-filter-interpreter.c index 5bf0bd60..6e5a5139 100644 --- a/lttng-filter-interpreter.c +++ b/lttng-filter-interpreter.c @@ -1,31 +1,14 @@ -/* +/* SPDX-License-Identifier: MIT + * * lttng-filter-interpreter.c * * LTTng modules filter interpreter. * * Copyright (C) 2010-2016 Mathieu Desnoyers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ -#include -#include +#include +#include #include #include @@ -39,7 +22,7 @@ LTTNG_STACK_FRAME_NON_STANDARD(lttng_filter_interpret_bytecode); * to handle user-space read. */ static -char get_char(struct estack_entry *reg, size_t offset) +char get_char(const struct estack_entry *reg, size_t offset) { if (unlikely(offset >= reg->u.s.seq_len)) return '\0'; @@ -47,7 +30,7 @@ char get_char(struct estack_entry *reg, size_t offset) char c; /* Handle invalid access as end of string. */ - if (unlikely(!access_ok(VERIFY_READ, + if (unlikely(!lttng_access_ok(VERIFY_READ, reg->u.s.user_str + offset, sizeof(c)))) return '\0'; @@ -98,16 +81,14 @@ 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; + /* Disable the page fault handler when reading from userspace. */ 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(); } @@ -123,10 +104,8 @@ int stack_star_glob_match(struct estack *stack, int top, const char *cmp_type) /* 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) { + if (has_user) pagefault_enable(); - set_fs(old_fs); - } return result; } @@ -136,13 +115,10 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) { size_t offset_bx = 0, offset_ax = 0; int diff, has_user = 0; - mm_segment_t old_fs; if (estack_bx(stack, top)->u.s.user || estack_ax(stack, top)->u.s.user) { has_user = 1; - old_fs = get_fs(); - set_fs(KERNEL_DS); pagefault_disable(); } @@ -227,10 +203,9 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) offset_bx++; offset_ax++; } - if (has_user) { + if (has_user) pagefault_enable(); - set_fs(old_fs); - } + return diff; } @@ -572,7 +547,7 @@ static int dynamic_load_field(struct estack_entry *stack_top) ret = -EINVAL; goto end; } - stack_top->u.s.seq_len = SIZE_MAX; + stack_top->u.s.seq_len = LTTNG_SIZE_MAX; stack_top->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; break; @@ -618,6 +593,39 @@ end: return ret; } +#ifdef DEBUG + +#define DBG_USER_STR_CUTOFF 32 + +/* + * In debug mode, print user string (truncated, if necessary). + */ +static inline +void dbg_load_ref_user_str_printk(const struct estack_entry *user_str_reg) +{ + size_t pos = 0; + char last_char; + char user_str[DBG_USER_STR_CUTOFF]; + + pagefault_disable(); + do { + last_char = get_char(user_str_reg, pos); + user_str[pos] = last_char; + pos++; + } while (last_char != '\0' && pos < sizeof(user_str)); + pagefault_enable(); + + user_str[sizeof(user_str) - 1] = '\0'; + dbg_printk("load field ref user string: '%s%s'\n", user_str, + last_char != '\0' ? "[...]" : ""); +} +#else +static inline +void dbg_load_ref_user_str_printk(const struct estack_entry *user_str_reg) +{ +} +#endif + /* * Return 0 (discard), or raise the 0x1 flag (log event). * Currently, other flags are kept for future extensions and have no @@ -771,6 +779,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, [ FILTER_OP_LOAD_FIELD_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_FIELD_DOUBLE, [ FILTER_OP_UNARY_BIT_NOT ] = &&LABEL_FILTER_OP_UNARY_BIT_NOT, + + [ FILTER_OP_RETURN_S64 ] = &&LABEL_FILTER_OP_RETURN_S64, }; #endif /* #ifndef INTERPRETER_USE_SWITCH */ @@ -788,6 +798,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; OP(FILTER_OP_RETURN): + OP(FILTER_OP_RETURN_S64): /* LTTNG_FILTER_DISCARD or LTTNG_FILTER_RECORD_FLAG */ retval = !!estack_ax_v; ret = 0; @@ -990,7 +1001,12 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { int64_t res; - res = (estack_bx_v >> estack_ax_v); + /* Catch undefined behavior. */ + if (unlikely(estack_ax_v < 0 || estack_ax_v >= 64)) { + ret = -EINVAL; + goto end; + } + res = ((uint64_t) estack_bx_v >> (uint32_t) estack_ax_v); estack_pop(stack, top, ax, bx); estack_ax_v = res; next_pc += sizeof(struct binary_op); @@ -1000,7 +1016,12 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { int64_t res; - res = (estack_bx_v << estack_ax_v); + /* Catch undefined behavior. */ + if (unlikely(estack_ax_v < 0 || estack_ax_v >= 64)) { + ret = -EINVAL; + goto end; + } + res = ((uint64_t) estack_bx_v << (uint32_t) estack_ax_v); estack_pop(stack, top, ax, bx); estack_ax_v = res; next_pc += sizeof(struct binary_op); @@ -1010,7 +1031,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { int64_t res; - res = (estack_bx_v & estack_ax_v); + res = ((uint64_t) estack_bx_v & (uint64_t) estack_ax_v); estack_pop(stack, top, ax, bx); estack_ax_v = res; next_pc += sizeof(struct binary_op); @@ -1020,7 +1041,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { int64_t res; - res = (estack_bx_v | estack_ax_v); + res = ((uint64_t) estack_bx_v | (uint64_t) estack_ax_v); estack_pop(stack, top, ax, bx); estack_ax_v = res; next_pc += sizeof(struct binary_op); @@ -1030,7 +1051,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { int64_t res; - res = (estack_bx_v ^ estack_ax_v); + res = ((uint64_t) estack_bx_v ^ (uint64_t) estack_ax_v); estack_pop(stack, top, ax, bx); estack_ax_v = res; next_pc += sizeof(struct binary_op); @@ -1049,7 +1070,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_UNARY_BIT_NOT): { - estack_ax_v = ~estack_ax_v; + estack_ax_v = ~(uint64_t) estack_ax_v; next_pc += sizeof(struct unary_op); PO; } @@ -1325,7 +1346,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, estack_push(stack, top, ax, bx); estack_ax(stack, top)->u.s.user_str = *(const char * const *) &filter_stack_data[ref->offset]; - if (unlikely(!estack_ax(stack, top)->u.s.str)) { + if (unlikely(!estack_ax(stack, top)->u.s.user_str)) { dbg_printk("Filter warning: loading a NULL string.\n"); ret = -EINVAL; goto end; @@ -1334,7 +1355,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, 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); + dbg_load_ref_user_str_printk(estack_ax(stack, top)); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; } @@ -1352,7 +1373,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, estack_ax(stack, top)->u.s.user_str = *(const char **) (&filter_stack_data[ref->offset + sizeof(unsigned long)]); - if (unlikely(!estack_ax(stack, top)->u.s.str)) { + if (unlikely(!estack_ax(stack, top)->u.s.user_str)) { dbg_printk("Filter warning: loading a NULL sequence.\n"); ret = -EINVAL; goto end; @@ -1546,7 +1567,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, ret = -EINVAL; goto end; } - estack_ax(stack, top)->u.s.seq_len = SIZE_MAX; + estack_ax(stack, top)->u.s.seq_len = LTTNG_SIZE_MAX; estack_ax(stack, top)->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; next_pc += sizeof(struct load_op);