static void validate_lex_operand(Validator *val, MVMuint32 flags) { MVMuint16 lex_index, frame_index, i; MVMuint32 lex_count; MVMStaticFrame *frame = val->frame; /* Two steps forward, two steps back to keep the error reporting happy, and to make the endian conversion within ensure_bytes correct. (Both are using val->cur_op, and want it to have different values.) */ ensure_bytes(val, 2); lex_index = GET_UI16(val->cur_op, 0); val->cur_op += 2; ensure_bytes(val, 2); val->cur_op -= 2; frame_index = GET_UI16(val->cur_op, 2); for (i = frame_index; i; i--) { frame = frame->body.outer; if (!frame) fail(val, MSG(val, "lexical operand requires %" PRIu16 " more enclosing scopes"), i); } lex_count = frame->body.num_lexicals; if (lex_index >= lex_count) fail(val, MSG(val, "lexical operand index %" PRIu16 " out of range 0.. %" PRIu32), lex_index, lex_count - 1); val->cur_op += 4; }
static void validate_reg_operand(Validator *val, MVMuint32 flags) { MVMuint32 operand_type = flags & MVM_operand_type_mask; MVMuint32 reg_type; MVMuint16 reg; ensure_bytes(val, 2); reg = GET_REG(val->cur_op, 0); if (reg >= val->loc_count) fail(val, MSG(val, "register operand index %" PRIu16 " out of range 0..%" PRIu32), reg, val->loc_count - 1); reg_type = val->loc_types[reg] << 3; if (operand_type == MVM_operand_type_var) { if (!val->reg_type_var) { val->reg_type_var = reg_type; goto next_operand; } operand_type = val->reg_type_var; } if (reg_type != operand_type) fail(val, MSG(val, "operand type %i does not match register type %i"), operand_type, reg_type); next_operand: val->cur_op += 2; }
MVM_STATIC_INLINE void read_op(Validator *val) { MVMuint16 opcode; const MVMOpInfo *info; MVMuint32 pos; ensure_bytes(val, 2); opcode = *(MVMuint16 *)val->cur_op; info = get_info(val, opcode); pos = val->cur_op - val->bc_start; #if 0 MVM_string_print(val->tc, val->cu->body.filename); printf(" %u %s %.2s\n", val->cur_instr, info->name, info->mark); #endif val->labels[pos] |= MVM_BC_op_boundary; val->cur_info = info; val->cur_mark = info->mark; val->cur_op += 2; val->cur_instr += 1; }
static void validate_literal_operand(Validator *val, MVMuint32 flags) { MVMuint32 type = flags & MVM_operand_type_mask; MVMuint32 size; switch (type) { case MVM_operand_int8: size = 1; break; case MVM_operand_int16: size = 2; break; case MVM_operand_int32: size = 4; break; case MVM_operand_int64: size = 8; break; case MVM_operand_num32: size = 4; break; case MVM_operand_num64: size = 8; break; case MVM_operand_callsite: size = 2; break; case MVM_operand_coderef: size = 2; break; case MVM_operand_str: size = 4; break; case MVM_operand_ins: size = 4; break; case MVM_operand_obj: case MVM_operand_type_var: fail(val, MSG(val, "operand type %i can't be a literal"), type); default: fail(val, MSG(val, "unknown operand type %i"), type); } ensure_bytes(val, size); switch (type) { case MVM_operand_callsite: { MVMuint16 index = GET_UI16(val->cur_op, 0); MVMuint32 count = val->cu->body.orig_callsites; if (index >= count) fail(val, MSG(val, "callsite index %" PRIu16 " out of range 0..%" PRIu32), index, count - 1); break; } case MVM_operand_coderef: { MVMuint16 index = GET_UI16(val->cur_op, 0); MVMuint32 count = val->cu->body.orig_frames; if (index >= count) fail(val, MSG(val, "coderef index %" PRIu16 " out of range 0..%" PRIu32), index, count - 1); break; } case MVM_operand_str: { MVMuint32 index = GET_UI32(val->cur_op, 0); MVMuint32 count = val->cu->body.orig_strings; if (index >= count) fail(val, MSG(val, "string index %" PRIu32 " out of range 0..%" PRIu32), index, count - 1); break; } case MVM_operand_ins: { MVMuint32 offset = GET_UI32(val->cur_op, 0); if (offset >= val->bc_size) fail(val, MSG(val, "branch instruction offset %" PRIu32 " out of range 0..%" PRIu32), offset, val->bc_size - 1); val->labels[offset] |= MVM_BC_branch_target; } } val->cur_op += size; }
static int handle_global_update(enum global_type type, size_t size, unsigned char *value) { struct global_config *config; bool timer_needs_update = false; enum session_timer_type timer_type; int error; config = kmalloc(sizeof(*config), GFP_KERNEL); if (!config) return -ENOMEM; config->mtu_plateaus = NULL; error = config_clone(config); if (error) goto fail; switch (type) { #ifdef STATEFUL case MAX_PKTS: if (!ensure_bytes(size, 8)) goto einval; config->max_stored_pkts = *((__u64 *) value); break; case SRC_ICMP6ERRS_BETTER: if (!ensure_bytes(size, 1)) goto einval; config->src_icmp6errs_better = *((__u8 *) value); break; case BIB_LOGGING: if (!ensure_bytes(size, 1)) goto einval; config->bib_logging = *((__u8 *) value); break; case SESSION_LOGGING: if (!ensure_bytes(size, 1)) goto einval; config->session_logging = *((__u8 *) value); break; case UDP_TIMEOUT: if (!ensure_bytes(size, 8)) goto einval; if (!assign_timeout(value, UDP_MIN, &config->ttl.udp)) goto einval; timer_needs_update = true; timer_type = SESSIONTIMER_UDP; break; case ICMP_TIMEOUT: if (!ensure_bytes(size, 8)) goto einval; if (!assign_timeout(value, 0, &config->ttl.icmp)) goto einval; timer_needs_update = true; timer_type = SESSIONTIMER_ICMP; break; case TCP_EST_TIMEOUT: if (!ensure_bytes(size, 8)) goto einval; if (!assign_timeout(value, TCP_EST, &config->ttl.tcp_est)) goto einval; timer_needs_update = true; timer_type = SESSIONTIMER_EST; break; case TCP_TRANS_TIMEOUT: if (!ensure_bytes(size, 8)) goto einval; if (!assign_timeout(value, TCP_TRANS, &config->ttl.tcp_trans)) goto einval; timer_needs_update = true; timer_type = SESSIONTIMER_TRANS; break; case FRAGMENT_TIMEOUT: if (!ensure_bytes(size, 8)) goto einval; if (!assign_timeout(value, FRAGMENT_MIN, &config->ttl.frag)) goto einval; break; case DROP_BY_ADDR: if (!ensure_bytes(size, 1)) goto einval; config->drop_by_addr = *((__u8 *) value); break; case DROP_ICMP6_INFO: if (!ensure_bytes(size, 1)) goto einval; config->drop_icmp6_info = *((__u8 *) value); break; case DROP_EXTERNAL_TCP: if (!ensure_bytes(size, 1)) goto einval; config->drop_external_tcp = *((__u8 *) value); break; #else case COMPUTE_UDP_CSUM_ZERO: if (!ensure_bytes(size, 1)) goto einval; config->compute_udp_csum_zero = *((__u8 *) value); break; case RANDOMIZE_RFC6791: if (!ensure_bytes(size, 1)) goto einval; config->randomize_error_addresses = *((__u8 *) value); break; #endif case RESET_TCLASS: if (!ensure_bytes(size, 1)) goto einval; config->reset_traffic_class = *((__u8 *) value); break; case RESET_TOS: if (!ensure_bytes(size, 1)) goto einval; config->reset_tos = *((__u8 *) value); break; case NEW_TOS: if (!ensure_bytes(size, 1)) goto einval; config->new_tos = *((__u8 *) value); break; case DF_ALWAYS_ON: if (!ensure_bytes(size, 1)) goto einval; config->atomic_frags.df_always_on = *((__u8 *) value); break; case BUILD_IPV6_FH: if (!ensure_bytes(size, 1)) goto einval; config->atomic_frags.build_ipv6_fh = *((__u8 *) value); break; case BUILD_IPV4_ID: if (!ensure_bytes(size, 1)) goto einval; config->atomic_frags.build_ipv4_id = *((__u8 *) value); break; case LOWER_MTU_FAIL: if (!ensure_bytes(size, 1)) goto einval; config->atomic_frags.lower_mtu_fail = *((__u8 *) value); break; case MTU_PLATEAUS: if (is_error(update_plateaus(config, size, value))) goto einval; break; case DISABLE: config->is_disable = (__u8) true; break; case ENABLE: config->is_disable = (__u8) false; break; case ATOMIC_FRAGMENTS: if (!ensure_bytes(size, 1)) goto einval; config->atomic_frags.df_always_on = *((__u8 *) value); config->atomic_frags.build_ipv6_fh = *((__u8 *) value); config->atomic_frags.build_ipv4_id = !(*((__u8 *) value)); config->atomic_frags.lower_mtu_fail = !(*((__u8 *) value)); break; default: log_err("Unknown config type: %u", type); goto einval; } error = config_set(config); if (error) goto fail; if (timer_needs_update) error = sessiondb_update_timer(timer_type); return error; einval: error = -EINVAL; /* Fall through. */ fail: kfree(config->mtu_plateaus); kfree(config); return error; }