mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	bpf: reject stores into ctx via st and xadd
Alexei found that verifier does not reject stores into context
via BPF_ST instead of BPF_STX. And while looking at it, we
also should not allow XADD variant of BPF_STX.
The context rewriter is only assuming either BPF_LDX_MEM- or
BPF_STX_MEM-type operations, thus reject anything other than
that so that assumptions in the rewriter properly hold. Add
test cases as well for BPF selftests.
Fixes: d691f9e8d4 ("bpf: allow programs to write to certain skb fields")
Reported-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									a2284d912b
								
							
						
					
					
						commit
						f37a8cb84c
					
				
					 2 changed files with 46 additions and 2 deletions
				
			
		| 
						 | 
					@ -978,6 +978,13 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
 | 
				
			||||||
	return __is_pointer_value(env->allow_ptr_leaks, cur_regs(env) + regno);
 | 
						return __is_pointer_value(env->allow_ptr_leaks, cur_regs(env) + regno);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool is_ctx_reg(struct bpf_verifier_env *env, int regno)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct bpf_reg_state *reg = cur_regs(env) + regno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return reg->type == PTR_TO_CTX;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int check_pkt_ptr_alignment(struct bpf_verifier_env *env,
 | 
					static int check_pkt_ptr_alignment(struct bpf_verifier_env *env,
 | 
				
			||||||
				   const struct bpf_reg_state *reg,
 | 
									   const struct bpf_reg_state *reg,
 | 
				
			||||||
				   int off, int size, bool strict)
 | 
									   int off, int size, bool strict)
 | 
				
			||||||
| 
						 | 
					@ -1258,6 +1265,12 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins
 | 
				
			||||||
		return -EACCES;
 | 
							return -EACCES;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_ctx_reg(env, insn->dst_reg)) {
 | 
				
			||||||
 | 
							verbose(env, "BPF_XADD stores into R%d context is not allowed\n",
 | 
				
			||||||
 | 
								insn->dst_reg);
 | 
				
			||||||
 | 
							return -EACCES;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check whether atomic_add can read the memory */
 | 
						/* check whether atomic_add can read the memory */
 | 
				
			||||||
	err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
 | 
						err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
 | 
				
			||||||
			       BPF_SIZE(insn->code), BPF_READ, -1);
 | 
								       BPF_SIZE(insn->code), BPF_READ, -1);
 | 
				
			||||||
| 
						 | 
					@ -3993,6 +4006,12 @@ static int do_check(struct bpf_verifier_env *env)
 | 
				
			||||||
			if (err)
 | 
								if (err)
 | 
				
			||||||
				return err;
 | 
									return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (is_ctx_reg(env, insn->dst_reg)) {
 | 
				
			||||||
 | 
									verbose(env, "BPF_ST stores into R%d context is not allowed\n",
 | 
				
			||||||
 | 
										insn->dst_reg);
 | 
				
			||||||
 | 
									return -EACCES;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* check that memory (dst_reg + off) is writeable */
 | 
								/* check that memory (dst_reg + off) is writeable */
 | 
				
			||||||
			err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
 | 
								err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
 | 
				
			||||||
					       BPF_SIZE(insn->code), BPF_WRITE,
 | 
										       BPF_SIZE(insn->code), BPF_WRITE,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2592,6 +2592,29 @@ static struct bpf_test tests[] = {
 | 
				
			||||||
		.result = ACCEPT,
 | 
							.result = ACCEPT,
 | 
				
			||||||
		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
 | 
							.prog_type = BPF_PROG_TYPE_SCHED_CLS,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							"context stores via ST",
 | 
				
			||||||
 | 
							.insns = {
 | 
				
			||||||
 | 
								BPF_MOV64_IMM(BPF_REG_0, 0),
 | 
				
			||||||
 | 
								BPF_ST_MEM(BPF_DW, BPF_REG_1, offsetof(struct __sk_buff, mark), 0),
 | 
				
			||||||
 | 
								BPF_EXIT_INSN(),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.errstr = "BPF_ST stores into R1 context is not allowed",
 | 
				
			||||||
 | 
							.result = REJECT,
 | 
				
			||||||
 | 
							.prog_type = BPF_PROG_TYPE_SCHED_CLS,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							"context stores via XADD",
 | 
				
			||||||
 | 
							.insns = {
 | 
				
			||||||
 | 
								BPF_MOV64_IMM(BPF_REG_0, 0),
 | 
				
			||||||
 | 
								BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_W, BPF_REG_1,
 | 
				
			||||||
 | 
									     BPF_REG_0, offsetof(struct __sk_buff, mark), 0),
 | 
				
			||||||
 | 
								BPF_EXIT_INSN(),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							.errstr = "BPF_XADD stores into R1 context is not allowed",
 | 
				
			||||||
 | 
							.result = REJECT,
 | 
				
			||||||
 | 
							.prog_type = BPF_PROG_TYPE_SCHED_CLS,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		"direct packet access: test1",
 | 
							"direct packet access: test1",
 | 
				
			||||||
		.insns = {
 | 
							.insns = {
 | 
				
			||||||
| 
						 | 
					@ -4312,7 +4335,8 @@ static struct bpf_test tests[] = {
 | 
				
			||||||
		.fixup_map1 = { 2 },
 | 
							.fixup_map1 = { 2 },
 | 
				
			||||||
		.errstr_unpriv = "R2 leaks addr into mem",
 | 
							.errstr_unpriv = "R2 leaks addr into mem",
 | 
				
			||||||
		.result_unpriv = REJECT,
 | 
							.result_unpriv = REJECT,
 | 
				
			||||||
		.result = ACCEPT,
 | 
							.result = REJECT,
 | 
				
			||||||
 | 
							.errstr = "BPF_XADD stores into R1 context is not allowed",
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		"leak pointer into ctx 2",
 | 
							"leak pointer into ctx 2",
 | 
				
			||||||
| 
						 | 
					@ -4326,7 +4350,8 @@ static struct bpf_test tests[] = {
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		.errstr_unpriv = "R10 leaks addr into mem",
 | 
							.errstr_unpriv = "R10 leaks addr into mem",
 | 
				
			||||||
		.result_unpriv = REJECT,
 | 
							.result_unpriv = REJECT,
 | 
				
			||||||
		.result = ACCEPT,
 | 
							.result = REJECT,
 | 
				
			||||||
 | 
							.errstr = "BPF_XADD stores into R1 context is not allowed",
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		"leak pointer into ctx 3",
 | 
							"leak pointer into ctx 3",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue