Patch "bpf: don't (ab)use instructions to store state" has been added to the 4.4-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
bpf: don't (ab)use instructions to store state
to the 4.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
bpf-don-t-ab-use-instructions-to-store-state.patch
and it can be found in the queue-4.4 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
3df126f35f88dc76eea33769f85a3c3bb8ce6c6bMon Sep 17 00:00:00 2001
From: Jakub Kicinski <[email protected]>
Date: Wed, 21 Sep 2016 11:43:56 +0100
Subject: bpf: don't (ab)use instructions to store state
From: Jakub Kicinski <[email protected]>
commit 3df126f35f88dc76eea33769f85a3c3bb8ce6c6b upstream.
Storing state in reserved fields of instructions makes it impossible to run verifier on programs already marked as read-only. Allocate and use an array of per-instruction state instead.
While touching the error path rename and move existing jump target.
--- kernel/bpf/verifier.c | 67 +++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 28 deletions(-)
kernel/bpf/verifier.c +39 -28
@@ -186,6 +186,10 @@ struct verifier_stack_elem {struct verifier_stack_elem *next; }; +struct bpf_insn_aux_data { +enum bpf_reg_type ptr_type;/* pointer type for load/store insns */ +}; +#define MAX_USED_MAPS 64/* max number of maps accessed by one eBPF program */ /* single container for all structs
@@ -200,6 +204,7 @@ struct verifier_env {struct bpf_map *used_maps[MAX_USED_MAPS ];/* array of map's used by eBPF program */ u32 used_map_cnt;/* number of used maps */ bool allow_ptr_leaks; +struct bpf_insn_aux_data *insn_aux_data;/* array of per-insn state */ };/* verbose verifier prints what it's seeing
@@ -1784,7 +1789,7 @@ static int do_check(struct verifier_envreturn err; }else if (class ==BPF_LDX ) { -enum bpf_reg_type src_reg_type; +enum bpf_reg_type *prev_src_type, src_reg_type;/* check for reserved fields is already done */
@@ -1813,16 +1818,18 @@ static int do_check(struct verifier_envcontinue ; } -if (insn->imm ==0 ) { + prev_src_type = &env->insn_aux_data[insn_idx].ptr_type; + +if (*prev_src_type ==NOT_INIT ) {/* saw a valid insn * dst_reg = *(u32 *)(src_reg + off) -* use reserved 'imm' field to mark this insn +* save type to validate intersecting paths */ - insn->imm = src_reg_type; + *prev_src_type = src_reg_type; - }else if (src_reg_type != insn->imm && + }else if (src_reg_type != *prev_src_type && (src_reg_type ==PTR_TO_CTX || - insn->imm ==PTR_TO_CTX )) { + *prev_src_type ==PTR_TO_CTX )) {/* ABuser program is trying to use the same insn * dst_reg = *(u32*) (src_reg + off) * with different pointer types:
@@ -1835,7 +1842,7 @@ static int do_check(struct verifier_env } }else if (class ==BPF_STX ) { -enum bpf_reg_type dst_reg_type; +enum bpf_reg_type *prev_dst_type, dst_reg_type;if (BPF_MODE (insn->code) ==BPF_XADD ) { err =check_xadd (env, insn);
@@ -1863,11 +1870,13 @@ static int do_check(struct verifier_envif (err)return err; -if (insn->imm ==0 ) { - insn->imm = dst_reg_type; - }else if (dst_reg_type != insn->imm && + prev_dst_type = &env->insn_aux_data[insn_idx].ptr_type; + +if (*prev_dst_type ==NOT_INIT ) { + *prev_dst_type = dst_reg_type; + }else if (dst_reg_type != *prev_dst_type && (dst_reg_type ==PTR_TO_CTX || - insn->imm ==PTR_TO_CTX )) { + *prev_dst_type ==PTR_TO_CTX )) {verbose ("same insn cannot be used with different pointers\n" );return -EINVAL ; }
@@ -2104,17 +2113,17 @@ static void convert_pseudo_ld_imm64(strustatic int convert_ctx_accesses (struct verifier_env *env) {struct bpf_insn *insn = env->prog->insnsi; -int insn_cnt = env->prog->len; +const int insn_cnt = env->prog->len;struct bpf_insn insn_buf[16 ];struct bpf_prog *new_prog;enum bpf_access_type type; -int i; +int i, delta =0 ;if (!env->prog->aux->ops->convert_ctx_access)return 0 ;for (i =0 ; i < insn_cnt; i++, insn++) { -u32 insn_delta, cnt; +u32 cnt;if (insn->code == (BPF_LDX |BPF_MEM |BPF_W )) type =BPF_READ ;
@@ -2123,11 +2132,8 @@ static int convert_ctx_accesses(struct velse continue ; -if (insn->imm !=PTR_TO_CTX ) { -/* clear internal mark */ - insn->imm =0 ; +if (env->insn_aux_data[i].ptr_type !=PTR_TO_CTX )continue ; - } cnt = env->prog->aux->ops-> convert_ctx_access(type, insn->dst_reg, insn->src_reg,
@@ -2137,18 +2143,16 @@ static int convert_ctx_accesses(struct vreturn -EINVAL ; } - new_prog =bpf_patch_insn_single (env->prog, i, insn_buf, cnt); + new_prog =bpf_patch_insn_single (env->prog, i + delta, insn_buf, + cnt);if (!new_prog)return -ENOMEM ; - insn_delta = cnt -1 ; + delta += cnt -1 ;/* keep walking new program and skip insns we just inserted */ env->prog = new_prog; - insn = new_prog->insnsi + i + insn_delta; - - insn_cnt += insn_delta; - i += insn_delta; + insn = new_prog->insnsi + i + delta; }return 0 ;
@@ -2192,6 +2196,11 @@ int bpf_check(struct bpf_prog **prog, unif (!env)return -ENOMEM ; + env->insn_aux_data =vzalloc (sizeof (struct bpf_insn_aux_data ) * + (*prog)->len); + ret = -ENOMEM ; +if (!env->insn_aux_data) + goto err_free_env; env->prog = *prog;/* grab the mutex to protect few globals used by verifier */
@@ -2210,12 +2219,12 @@ int bpf_check(struct bpf_prog **prog, un/* log_* values have to be sane */ if (log_size <128 || log_size >UINT_MAX >>8 || log_level ==0 || log_ubuf ==NULL ) - goto free_env; + goto err_unlock; ret = -ENOMEM ; log_buf =vmalloc (log_size);if (!log_buf) - goto free_env; + goto err_unlock; }else { log_level =0 ; }
@@ -2284,14 +2293,16 @@ skip_full_check: free_log_buf:if (log_level)vfree (log_buf); -free_env:if (!env->prog->aux->used_maps)/* if we didn't copy map pointers into bpf_prog_info, release * them now. Otherwise free_bpf_prog_info() will release them. */ release_maps (env); *prog = env->prog; -kfree (env); +err_unlock:mutex_unlock (&bpf_verifier_lock); +vfree (env->insn_aux_data); +err_free_env: +kfree (env);return ret; }
Patches currently in stable-queue which might be from [email protected] are
queue-4.4/bpf-don-t-ab-use-instructions-to-store-state.patch