diff options
Diffstat (limited to 'kernel/bpf')
| -rw-r--r-- | kernel/bpf/arraymap.c | 1 | ||||
| -rw-r--r-- | kernel/bpf/lpm_trie.c | 1 | ||||
| -rw-r--r-- | kernel/bpf/stackmap.c | 1 | ||||
| -rw-r--r-- | kernel/bpf/syscall.c | 5 | ||||
| -rw-r--r-- | kernel/bpf/verifier.c | 192 | 
5 files changed, 153 insertions, 47 deletions
| diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 5e00b2333c26..172dc8ee0e3b 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -86,6 +86,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)  	array->map.key_size = attr->key_size;  	array->map.value_size = attr->value_size;  	array->map.max_entries = attr->max_entries; +	array->map.map_flags = attr->map_flags;  	array->elem_size = elem_size;  	if (!percpu) diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c index 39cfafd895b8..b09185f0f17d 100644 --- a/kernel/bpf/lpm_trie.c +++ b/kernel/bpf/lpm_trie.c @@ -432,6 +432,7 @@ static struct bpf_map *trie_alloc(union bpf_attr *attr)  	trie->map.key_size = attr->key_size;  	trie->map.value_size = attr->value_size;  	trie->map.max_entries = attr->max_entries; +	trie->map.map_flags = attr->map_flags;  	trie->data_size = attr->key_size -  			  offsetof(struct bpf_lpm_trie_key, data);  	trie->max_prefixlen = trie->data_size * 8; diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 4dfd6f2ec2f9..31147d730abf 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -88,6 +88,7 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr)  	smap->map.key_size = attr->key_size;  	smap->map.value_size = value_size;  	smap->map.max_entries = attr->max_entries; +	smap->map.map_flags = attr->map_flags;  	smap->n_buckets = n_buckets;  	smap->map.pages = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index fd2411fd6914..265a0d854e33 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -783,7 +783,7 @@ struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type)  EXPORT_SYMBOL_GPL(bpf_prog_get_type);  /* last field in 'union bpf_attr' used by this command */ -#define	BPF_PROG_LOAD_LAST_FIELD kern_version +#define	BPF_PROG_LOAD_LAST_FIELD prog_flags  static int bpf_prog_load(union bpf_attr *attr)  { @@ -796,6 +796,9 @@ static int bpf_prog_load(union bpf_attr *attr)  	if (CHECK_ATTR(BPF_PROG_LOAD))  		return -EINVAL; +	if (attr->prog_flags & ~BPF_F_STRICT_ALIGNMENT) +		return -EINVAL; +  	/* copy eBPF program license from user space */  	if (strncpy_from_user(license, u64_to_user_ptr(attr->license),  			      sizeof(license) - 1) < 0) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c5b56c92f8e2..a8a725697bed 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -140,7 +140,7 @@ struct bpf_verifier_stack_elem {  	struct bpf_verifier_stack_elem *next;  }; -#define BPF_COMPLEXITY_LIMIT_INSNS	65536 +#define BPF_COMPLEXITY_LIMIT_INSNS	98304  #define BPF_COMPLEXITY_LIMIT_STACK	1024  #define BPF_MAP_PTR_POISON ((void *)0xeB9F + POISON_POINTER_DELTA) @@ -241,6 +241,12 @@ static void print_verifier_state(struct bpf_verifier_state *state)  		if (reg->max_value != BPF_REGISTER_MAX_RANGE)  			verbose(",max_value=%llu",  				(unsigned long long)reg->max_value); +		if (reg->min_align) +			verbose(",min_align=%u", reg->min_align); +		if (reg->aux_off) +			verbose(",aux_off=%u", reg->aux_off); +		if (reg->aux_off_align) +			verbose(",aux_off_align=%u", reg->aux_off_align);  	}  	for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) {  		if (state->stack_slot_type[i] == STACK_SPILL) @@ -457,16 +463,22 @@ static const int caller_saved[CALLER_SAVED_REGS] = {  	BPF_REG_0, BPF_REG_1, BPF_REG_2, BPF_REG_3, BPF_REG_4, BPF_REG_5  }; +static void mark_reg_not_init(struct bpf_reg_state *regs, u32 regno) +{ +	BUG_ON(regno >= MAX_BPF_REG); + +	memset(®s[regno], 0, sizeof(regs[regno])); +	regs[regno].type = NOT_INIT; +	regs[regno].min_value = BPF_REGISTER_MIN_RANGE; +	regs[regno].max_value = BPF_REGISTER_MAX_RANGE; +} +  static void init_reg_state(struct bpf_reg_state *regs)  {  	int i; -	for (i = 0; i < MAX_BPF_REG; i++) { -		regs[i].type = NOT_INIT; -		regs[i].imm = 0; -		regs[i].min_value = BPF_REGISTER_MIN_RANGE; -		regs[i].max_value = BPF_REGISTER_MAX_RANGE; -	} +	for (i = 0; i < MAX_BPF_REG; i++) +		mark_reg_not_init(regs, i);  	/* frame pointer */  	regs[BPF_REG_FP].type = FRAME_PTR; @@ -492,6 +504,7 @@ static void reset_reg_range_values(struct bpf_reg_state *regs, u32 regno)  {  	regs[regno].min_value = BPF_REGISTER_MIN_RANGE;  	regs[regno].max_value = BPF_REGISTER_MAX_RANGE; +	regs[regno].min_align = 0;  }  static void mark_reg_unknown_value_and_range(struct bpf_reg_state *regs, @@ -779,17 +792,37 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno)  }  static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg, -				   int off, int size) +				   int off, int size, bool strict)  { -	if (reg->id && size != 1) { -		verbose("Unknown alignment. Only byte-sized access allowed in packet access.\n"); -		return -EACCES; +	int ip_align; +	int reg_off; + +	/* Byte size accesses are always allowed. */ +	if (!strict || size == 1) +		return 0; + +	reg_off = reg->off; +	if (reg->id) { +		if (reg->aux_off_align % size) { +			verbose("Packet access is only %u byte aligned, %d byte access not allowed\n", +				reg->aux_off_align, size); +			return -EACCES; +		} +		reg_off += reg->aux_off;  	} -	/* skb->data is NET_IP_ALIGN-ed */ -	if ((NET_IP_ALIGN + reg->off + off) % size != 0) { +	/* For platforms that do not have a Kconfig enabling +	 * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS the value of +	 * NET_IP_ALIGN is universally set to '2'.  And on platforms +	 * that do set CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS, we get +	 * to this code only in strict mode where we want to emulate +	 * the NET_IP_ALIGN==2 checking.  Therefore use an +	 * unconditional IP align value of '2'. +	 */ +	ip_align = 2; +	if ((ip_align + reg_off + off) % size != 0) {  		verbose("misaligned packet access off %d+%d+%d size %d\n", -			NET_IP_ALIGN, reg->off, off, size); +			ip_align, reg_off, off, size);  		return -EACCES;  	} @@ -797,9 +830,9 @@ static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg,  }  static int check_val_ptr_alignment(const struct bpf_reg_state *reg, -				   int size) +				   int size, bool strict)  { -	if (size != 1) { +	if (strict && size != 1) {  		verbose("Unknown alignment. Only byte-sized access allowed in value access.\n");  		return -EACCES;  	} @@ -807,16 +840,17 @@ static int check_val_ptr_alignment(const struct bpf_reg_state *reg,  	return 0;  } -static int check_ptr_alignment(const struct bpf_reg_state *reg, +static int check_ptr_alignment(struct bpf_verifier_env *env, +			       const struct bpf_reg_state *reg,  			       int off, int size)  { +	bool strict = env->strict_alignment; +  	switch (reg->type) {  	case PTR_TO_PACKET: -		return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ? 0 : -		       check_pkt_ptr_alignment(reg, off, size); +		return check_pkt_ptr_alignment(reg, off, size, strict);  	case PTR_TO_MAP_VALUE_ADJ: -		return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ? 0 : -		       check_val_ptr_alignment(reg, size); +		return check_val_ptr_alignment(reg, size, strict);  	default:  		if (off % size != 0) {  			verbose("misaligned access off %d size %d\n", @@ -849,7 +883,7 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off,  	if (size < 0)  		return size; -	err = check_ptr_alignment(reg, off, size); +	err = check_ptr_alignment(env, reg, off, size);  	if (err)  		return err; @@ -883,6 +917,8 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off,  							 value_regno);  			/* note that reg.[id|off|range] == 0 */  			state->regs[value_regno].type = reg_type; +			state->regs[value_regno].aux_off = 0; +			state->regs[value_regno].aux_off_align = 0;  		}  	} else if (reg->type == FRAME_PTR || reg->type == PTR_TO_STACK) { @@ -953,6 +989,11 @@ static int check_xadd(struct bpf_verifier_env *env, struct bpf_insn *insn)  	if (err)  		return err; +	if (is_pointer_value(env, insn->src_reg)) { +		verbose("R%d leaks addr into mem\n", insn->src_reg); +		return -EACCES; +	} +  	/* check whether atomic_add can read the memory */  	err = check_mem_access(env, insn->dst_reg, insn->off,  			       BPF_SIZE(insn->code), BPF_READ, -1); @@ -1313,7 +1354,6 @@ static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx)  	struct bpf_verifier_state *state = &env->cur_state;  	const struct bpf_func_proto *fn = NULL;  	struct bpf_reg_state *regs = state->regs; -	struct bpf_reg_state *reg;  	struct bpf_call_arg_meta meta;  	bool changes_data;  	int i, err; @@ -1380,11 +1420,8 @@ static int check_call(struct bpf_verifier_env *env, int func_id, int insn_idx)  	}  	/* reset caller saved regs */ -	for (i = 0; i < CALLER_SAVED_REGS; i++) { -		reg = regs + caller_saved[i]; -		reg->type = NOT_INIT; -		reg->imm = 0; -	} +	for (i = 0; i < CALLER_SAVED_REGS; i++) +		mark_reg_not_init(regs, caller_saved[i]);  	/* update return register */  	if (fn->ret_type == RET_INTEGER) { @@ -1455,6 +1492,8 @@ add_imm:  		 */  		dst_reg->off += imm;  	} else { +		bool had_id; +  		if (src_reg->type == PTR_TO_PACKET) {  			/* R6=pkt(id=0,off=0,r=62) R7=imm22; r7 += r6 */  			tmp_reg = *dst_reg;  /* save r7 state */ @@ -1488,14 +1527,23 @@ add_imm:  				src_reg->imm);  			return -EACCES;  		} + +		had_id = (dst_reg->id != 0); +  		/* dst_reg stays as pkt_ptr type and since some positive  		 * integer value was added to the pointer, increment its 'id'  		 */  		dst_reg->id = ++env->id_gen; -		/* something was added to pkt_ptr, set range and off to zero */ +		/* something was added to pkt_ptr, set range to zero */ +		dst_reg->aux_off += dst_reg->off;  		dst_reg->off = 0;  		dst_reg->range = 0; +		if (had_id) +			dst_reg->aux_off_align = min(dst_reg->aux_off_align, +						     src_reg->min_align); +		else +			dst_reg->aux_off_align = src_reg->min_align;  	}  	return 0;  } @@ -1669,6 +1717,13 @@ static void check_reg_overflow(struct bpf_reg_state *reg)  		reg->min_value = BPF_REGISTER_MIN_RANGE;  } +static u32 calc_align(u32 imm) +{ +	if (!imm) +		return 1U << 31; +	return imm - ((imm - 1) & imm); +} +  static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,  				    struct bpf_insn *insn)  { @@ -1676,8 +1731,10 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,  	s64 min_val = BPF_REGISTER_MIN_RANGE;  	u64 max_val = BPF_REGISTER_MAX_RANGE;  	u8 opcode = BPF_OP(insn->code); +	u32 dst_align, src_align;  	dst_reg = ®s[insn->dst_reg]; +	src_align = 0;  	if (BPF_SRC(insn->code) == BPF_X) {  		check_reg_overflow(®s[insn->src_reg]);  		min_val = regs[insn->src_reg].min_value; @@ -1693,12 +1750,18 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,  		    regs[insn->src_reg].type != UNKNOWN_VALUE) {  			min_val = BPF_REGISTER_MIN_RANGE;  			max_val = BPF_REGISTER_MAX_RANGE; +			src_align = 0; +		} else { +			src_align = regs[insn->src_reg].min_align;  		}  	} else if (insn->imm < BPF_REGISTER_MAX_RANGE &&  		   (s64)insn->imm > BPF_REGISTER_MIN_RANGE) {  		min_val = max_val = insn->imm; +		src_align = calc_align(insn->imm);  	} +	dst_align = dst_reg->min_align; +  	/* We don't know anything about what was done to this register, mark it  	 * as unknown.  	 */ @@ -1723,18 +1786,21 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,  			dst_reg->min_value += min_val;  		if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)  			dst_reg->max_value += max_val; +		dst_reg->min_align = min(src_align, dst_align);  		break;  	case BPF_SUB:  		if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)  			dst_reg->min_value -= min_val;  		if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)  			dst_reg->max_value -= max_val; +		dst_reg->min_align = min(src_align, dst_align);  		break;  	case BPF_MUL:  		if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)  			dst_reg->min_value *= min_val;  		if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)  			dst_reg->max_value *= max_val; +		dst_reg->min_align = max(src_align, dst_align);  		break;  	case BPF_AND:  		/* Disallow AND'ing of negative numbers, ain't nobody got time @@ -1746,17 +1812,23 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,  		else  			dst_reg->min_value = 0;  		dst_reg->max_value = max_val; +		dst_reg->min_align = max(src_align, dst_align);  		break;  	case BPF_LSH:  		/* Gotta have special overflow logic here, if we're shifting  		 * more than MAX_RANGE then just assume we have an invalid  		 * range.  		 */ -		if (min_val > ilog2(BPF_REGISTER_MAX_RANGE)) +		if (min_val > ilog2(BPF_REGISTER_MAX_RANGE)) {  			dst_reg->min_value = BPF_REGISTER_MIN_RANGE; -		else if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE) -			dst_reg->min_value <<= min_val; - +			dst_reg->min_align = 1; +		} else { +			if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE) +				dst_reg->min_value <<= min_val; +			if (!dst_reg->min_align) +				dst_reg->min_align = 1; +			dst_reg->min_align <<= min_val; +		}  		if (max_val > ilog2(BPF_REGISTER_MAX_RANGE))  			dst_reg->max_value = BPF_REGISTER_MAX_RANGE;  		else if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE) @@ -1766,11 +1838,19 @@ static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,  		/* RSH by a negative number is undefined, and the BPF_RSH is an  		 * unsigned shift, so make the appropriate casts.  		 */ -		if (min_val < 0 || dst_reg->min_value < 0) +		if (min_val < 0 || dst_reg->min_value < 0) {  			dst_reg->min_value = BPF_REGISTER_MIN_RANGE; -		else +		} else {  			dst_reg->min_value =  				(u64)(dst_reg->min_value) >> min_val; +		} +		if (min_val < 0) { +			dst_reg->min_align = 1; +		} else { +			dst_reg->min_align >>= (u64) min_val; +			if (!dst_reg->min_align) +				dst_reg->min_align = 1; +		}  		if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)  			dst_reg->max_value >>= max_val;  		break; @@ -1872,6 +1952,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)  			regs[insn->dst_reg].imm = insn->imm;  			regs[insn->dst_reg].max_value = insn->imm;  			regs[insn->dst_reg].min_value = insn->imm; +			regs[insn->dst_reg].min_align = calc_align(insn->imm);  		}  	} else if (opcode > BPF_END) { @@ -2368,7 +2449,6 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)  {  	struct bpf_reg_state *regs = env->cur_state.regs;  	u8 mode = BPF_MODE(insn->code); -	struct bpf_reg_state *reg;  	int i, err;  	if (!may_access_skb(env->prog->type)) { @@ -2401,11 +2481,8 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)  	}  	/* reset caller saved regs to unreadable */ -	for (i = 0; i < CALLER_SAVED_REGS; i++) { -		reg = regs + caller_saved[i]; -		reg->type = NOT_INIT; -		reg->imm = 0; -	} +	for (i = 0; i < CALLER_SAVED_REGS; i++) +		mark_reg_not_init(regs, caller_saved[i]);  	/* mark destination R0 register as readable, since it contains  	 * the value fetched from the packet @@ -2564,6 +2641,7 @@ peek_stack:  				env->explored_states[t + 1] = STATE_LIST_MARK;  		} else {  			/* conditional jump with two edges */ +			env->explored_states[t] = STATE_LIST_MARK;  			ret = push_insn(t, t + 1, FALLTHROUGH, env);  			if (ret == 1)  				goto peek_stack; @@ -2615,7 +2693,8 @@ err_free:  /* the following conditions reduce the number of explored insns   * from ~140k to ~80k for ultra large programs that use a lot of ptr_to_packet   */ -static bool compare_ptrs_to_packet(struct bpf_reg_state *old, +static bool compare_ptrs_to_packet(struct bpf_verifier_env *env, +				   struct bpf_reg_state *old,  				   struct bpf_reg_state *cur)  {  	if (old->id != cur->id) @@ -2658,7 +2737,7 @@ static bool compare_ptrs_to_packet(struct bpf_reg_state *old,  	 * 'if (R4 > data_end)' and all further insn were already good with r=20,  	 * so they will be good with r=30 and we can prune the search.  	 */ -	if (old->off <= cur->off && +	if (!env->strict_alignment && old->off <= cur->off &&  	    old->off >= old->range && cur->off >= cur->range)  		return true; @@ -2722,8 +2801,14 @@ static bool states_equal(struct bpf_verifier_env *env,  		     rcur->type != NOT_INIT))  			continue; +		/* Don't care about the reg->id in this case. */ +		if (rold->type == PTR_TO_MAP_VALUE_OR_NULL && +		    rcur->type == PTR_TO_MAP_VALUE_OR_NULL && +		    rold->map_ptr == rcur->map_ptr) +			continue; +  		if (rold->type == PTR_TO_PACKET && rcur->type == PTR_TO_PACKET && -		    compare_ptrs_to_packet(rold, rcur)) +		    compare_ptrs_to_packet(env, rold, rcur))  			continue;  		return false; @@ -2856,8 +2941,15 @@ static int do_check(struct bpf_verifier_env *env)  			goto process_bpf_exit;  		} -		if (log_level && do_print_state) { -			verbose("\nfrom %d to %d:", prev_insn_idx, insn_idx); +		if (need_resched()) +			cond_resched(); + +		if (log_level > 1 || (log_level && do_print_state)) { +			if (log_level > 1) +				verbose("%d:", insn_idx); +			else +				verbose("\nfrom %d to %d:", +					prev_insn_idx, insn_idx);  			print_verifier_state(&env->cur_state);  			do_print_state = false;  		} @@ -3495,6 +3587,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)  		log_level = 0;  	} +	env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT); +	if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) +		env->strict_alignment = true; +  	ret = replace_map_fd_with_map_ptr(env);  	if (ret < 0)  		goto skip_full_check; @@ -3600,6 +3696,10 @@ int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops,  	log_level = 0; +	env->strict_alignment = false; +	if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) +		env->strict_alignment = true; +  	env->explored_states = kcalloc(env->prog->len,  				       sizeof(struct bpf_verifier_state_list *),  				       GFP_KERNEL); |