Skip to content

Commit c64b798

Browse files
joestringerborkmann
authored andcommitted
bpf: Add PTR_TO_SOCKET verifier type
Teach the verifier a little bit about a new type of pointer, a PTR_TO_SOCKET. This pointer type is accessed from BPF through the 'struct bpf_sock' structure. Signed-off-by: Joe Stringer <joe@wand.net.nz> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
1 parent 840b961 commit c64b798

File tree

4 files changed

+160
-26
lines changed

4 files changed

+160
-26
lines changed

include/linux/bpf.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ enum bpf_arg_type {
154154

155155
ARG_PTR_TO_CTX, /* pointer to context */
156156
ARG_ANYTHING, /* any (initialized) argument is ok */
157+
ARG_PTR_TO_SOCKET, /* pointer to bpf_sock */
157158
};
158159

159160
/* type of values returned from helper functions */
@@ -162,6 +163,7 @@ enum bpf_return_type {
162163
RET_VOID, /* function doesn't return anything */
163164
RET_PTR_TO_MAP_VALUE, /* returns a pointer to map elem value */
164165
RET_PTR_TO_MAP_VALUE_OR_NULL, /* returns a pointer to map elem value or NULL */
166+
RET_PTR_TO_SOCKET_OR_NULL, /* returns a pointer to a socket or NULL */
165167
};
166168

167169
/* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs
@@ -213,6 +215,8 @@ enum bpf_reg_type {
213215
PTR_TO_PACKET, /* reg points to skb->data */
214216
PTR_TO_PACKET_END, /* skb->data + headlen */
215217
PTR_TO_FLOW_KEYS, /* reg points to bpf_flow_keys */
218+
PTR_TO_SOCKET, /* reg points to struct bpf_sock */
219+
PTR_TO_SOCKET_OR_NULL, /* reg points to struct bpf_sock or NULL */
216220
};
217221

218222
/* The information passed from prog-specific *_is_valid_access
@@ -343,6 +347,11 @@ const struct bpf_func_proto *bpf_get_trace_printk_proto(void);
343347

344348
typedef unsigned long (*bpf_ctx_copy_t)(void *dst, const void *src,
345349
unsigned long off, unsigned long len);
350+
typedef u32 (*bpf_convert_ctx_access_t)(enum bpf_access_type type,
351+
const struct bpf_insn *src,
352+
struct bpf_insn *dst,
353+
struct bpf_prog *prog,
354+
u32 *target_size);
346355

347356
u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size,
348357
void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy);
@@ -836,4 +845,29 @@ extern const struct bpf_func_proto bpf_get_local_storage_proto;
836845
void bpf_user_rnd_init_once(void);
837846
u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
838847

848+
#if defined(CONFIG_NET)
849+
bool bpf_sock_is_valid_access(int off, int size, enum bpf_access_type type,
850+
struct bpf_insn_access_aux *info);
851+
u32 bpf_sock_convert_ctx_access(enum bpf_access_type type,
852+
const struct bpf_insn *si,
853+
struct bpf_insn *insn_buf,
854+
struct bpf_prog *prog,
855+
u32 *target_size);
856+
#else
857+
static inline bool bpf_sock_is_valid_access(int off, int size,
858+
enum bpf_access_type type,
859+
struct bpf_insn_access_aux *info)
860+
{
861+
return false;
862+
}
863+
static inline u32 bpf_sock_convert_ctx_access(enum bpf_access_type type,
864+
const struct bpf_insn *si,
865+
struct bpf_insn *insn_buf,
866+
struct bpf_prog *prog,
867+
u32 *target_size)
868+
{
869+
return 0;
870+
}
871+
#endif
872+
839873
#endif /* _LINUX_BPF_H */

include/linux/bpf_verifier.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ struct bpf_reg_state {
5858
* offset, so they can share range knowledge.
5959
* For PTR_TO_MAP_VALUE_OR_NULL this is used to share which map value we
6060
* came from, when one is tested for != NULL.
61+
* For PTR_TO_SOCKET this is used to share which pointers retain the
62+
* same reference to the socket, to determine proper reference freeing.
6163
*/
6264
u32 id;
6365
/* For scalar types (SCALAR_VALUE), this represents our knowledge of

kernel/bpf/verifier.c

Lines changed: 106 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ static const struct bpf_verifier_ops * const bpf_verifier_ops[] = {
8080
* (like pointer plus pointer becomes SCALAR_VALUE type)
8181
*
8282
* When verifier sees load or store instructions the type of base register
83-
* can be: PTR_TO_MAP_VALUE, PTR_TO_CTX, PTR_TO_STACK. These are three pointer
84-
* types recognized by check_mem_access() function.
83+
* can be: PTR_TO_MAP_VALUE, PTR_TO_CTX, PTR_TO_STACK, PTR_TO_SOCKET. These are
84+
* four pointer types recognized by check_mem_access() function.
8585
*
8686
* PTR_TO_MAP_VALUE means that this register is pointing to 'map element value'
8787
* and the range of [ptr, ptr + map's value_size) is accessible.
@@ -267,6 +267,8 @@ static const char * const reg_type_str[] = {
267267
[PTR_TO_PACKET_META] = "pkt_meta",
268268
[PTR_TO_PACKET_END] = "pkt_end",
269269
[PTR_TO_FLOW_KEYS] = "flow_keys",
270+
[PTR_TO_SOCKET] = "sock",
271+
[PTR_TO_SOCKET_OR_NULL] = "sock_or_null",
270272
};
271273

272274
static char slot_type_char[] = {
@@ -973,6 +975,8 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
973975
case PTR_TO_PACKET_END:
974976
case PTR_TO_FLOW_KEYS:
975977
case CONST_PTR_TO_MAP:
978+
case PTR_TO_SOCKET:
979+
case PTR_TO_SOCKET_OR_NULL:
976980
return true;
977981
default:
978982
return false;
@@ -1341,6 +1345,28 @@ static int check_flow_keys_access(struct bpf_verifier_env *env, int off,
13411345
return 0;
13421346
}
13431347

1348+
static int check_sock_access(struct bpf_verifier_env *env, u32 regno, int off,
1349+
int size, enum bpf_access_type t)
1350+
{
1351+
struct bpf_reg_state *regs = cur_regs(env);
1352+
struct bpf_reg_state *reg = &regs[regno];
1353+
struct bpf_insn_access_aux info;
1354+
1355+
if (reg->smin_value < 0) {
1356+
verbose(env, "R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n",
1357+
regno);
1358+
return -EACCES;
1359+
}
1360+
1361+
if (!bpf_sock_is_valid_access(off, size, t, &info)) {
1362+
verbose(env, "invalid bpf_sock access off=%d size=%d\n",
1363+
off, size);
1364+
return -EACCES;
1365+
}
1366+
1367+
return 0;
1368+
}
1369+
13441370
static bool __is_pointer_value(bool allow_ptr_leaks,
13451371
const struct bpf_reg_state *reg)
13461372
{
@@ -1459,6 +1485,9 @@ static int check_ptr_alignment(struct bpf_verifier_env *env,
14591485
*/
14601486
strict = true;
14611487
break;
1488+
case PTR_TO_SOCKET:
1489+
pointer_desc = "sock ";
1490+
break;
14621491
default:
14631492
break;
14641493
}
@@ -1726,6 +1755,14 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
17261755
err = check_flow_keys_access(env, off, size);
17271756
if (!err && t == BPF_READ && value_regno >= 0)
17281757
mark_reg_unknown(env, regs, value_regno);
1758+
} else if (reg->type == PTR_TO_SOCKET) {
1759+
if (t == BPF_WRITE) {
1760+
verbose(env, "cannot write into socket\n");
1761+
return -EACCES;
1762+
}
1763+
err = check_sock_access(env, regno, off, size, t);
1764+
if (!err && value_regno >= 0)
1765+
mark_reg_unknown(env, regs, value_regno);
17291766
} else {
17301767
verbose(env, "R%d invalid mem access '%s'\n", regno,
17311768
reg_type_str[reg->type]);
@@ -1948,6 +1985,10 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
19481985
err = check_ctx_reg(env, reg, regno);
19491986
if (err < 0)
19501987
return err;
1988+
} else if (arg_type == ARG_PTR_TO_SOCKET) {
1989+
expected_type = PTR_TO_SOCKET;
1990+
if (type != expected_type)
1991+
goto err_type;
19511992
} else if (arg_type_is_mem_ptr(arg_type)) {
19521993
expected_type = PTR_TO_STACK;
19531994
/* One exception here. In case function allows for NULL to be
@@ -2543,6 +2584,10 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
25432584
}
25442585
regs[BPF_REG_0].map_ptr = meta.map_ptr;
25452586
regs[BPF_REG_0].id = ++env->id_gen;
2587+
} else if (fn->ret_type == RET_PTR_TO_SOCKET_OR_NULL) {
2588+
mark_reg_known_zero(env, regs, BPF_REG_0);
2589+
regs[BPF_REG_0].type = PTR_TO_SOCKET_OR_NULL;
2590+
regs[BPF_REG_0].id = ++env->id_gen;
25462591
} else {
25472592
verbose(env, "unknown return type %d of func %s#%d\n",
25482593
fn->ret_type, func_id_name(func_id), func_id);
@@ -2680,6 +2725,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
26802725
return -EACCES;
26812726
case CONST_PTR_TO_MAP:
26822727
case PTR_TO_PACKET_END:
2728+
case PTR_TO_SOCKET:
2729+
case PTR_TO_SOCKET_OR_NULL:
26832730
verbose(env, "R%d pointer arithmetic on %s prohibited\n",
26842731
dst, reg_type_str[ptr_reg->type]);
26852732
return -EACCES;
@@ -3627,6 +3674,8 @@ static void mark_ptr_or_null_reg(struct bpf_reg_state *reg, u32 id,
36273674
} else {
36283675
reg->type = PTR_TO_MAP_VALUE;
36293676
}
3677+
} else if (reg->type == PTR_TO_SOCKET_OR_NULL) {
3678+
reg->type = PTR_TO_SOCKET;
36303679
}
36313680
/* We don't need id from this point onwards anymore, thus we
36323681
* should better reset it, so that state pruning has chances
@@ -4402,6 +4451,8 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
44024451
case CONST_PTR_TO_MAP:
44034452
case PTR_TO_PACKET_END:
44044453
case PTR_TO_FLOW_KEYS:
4454+
case PTR_TO_SOCKET:
4455+
case PTR_TO_SOCKET_OR_NULL:
44054456
/* Only valid matches are exact, which memcmp() above
44064457
* would have accepted
44074458
*/
@@ -4679,6 +4730,37 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
46794730
return 0;
46804731
}
46814732

4733+
/* Return true if it's OK to have the same insn return a different type. */
4734+
static bool reg_type_mismatch_ok(enum bpf_reg_type type)
4735+
{
4736+
switch (type) {
4737+
case PTR_TO_CTX:
4738+
case PTR_TO_SOCKET:
4739+
case PTR_TO_SOCKET_OR_NULL:
4740+
return false;
4741+
default:
4742+
return true;
4743+
}
4744+
}
4745+
4746+
/* If an instruction was previously used with particular pointer types, then we
4747+
* need to be careful to avoid cases such as the below, where it may be ok
4748+
* for one branch accessing the pointer, but not ok for the other branch:
4749+
*
4750+
* R1 = sock_ptr
4751+
* goto X;
4752+
* ...
4753+
* R1 = some_other_valid_ptr;
4754+
* goto X;
4755+
* ...
4756+
* R2 = *(u32 *)(R1 + 0);
4757+
*/
4758+
static bool reg_type_mismatch(enum bpf_reg_type src, enum bpf_reg_type prev)
4759+
{
4760+
return src != prev && (!reg_type_mismatch_ok(src) ||
4761+
!reg_type_mismatch_ok(prev));
4762+
}
4763+
46824764
static int do_check(struct bpf_verifier_env *env)
46834765
{
46844766
struct bpf_verifier_state *state;
@@ -4811,9 +4893,7 @@ static int do_check(struct bpf_verifier_env *env)
48114893
*/
48124894
*prev_src_type = src_reg_type;
48134895

4814-
} else if (src_reg_type != *prev_src_type &&
4815-
(src_reg_type == PTR_TO_CTX ||
4816-
*prev_src_type == PTR_TO_CTX)) {
4896+
} else if (reg_type_mismatch(src_reg_type, *prev_src_type)) {
48174897
/* ABuser program is trying to use the same insn
48184898
* dst_reg = *(u32*) (src_reg + off)
48194899
* with different pointer types:
@@ -4858,9 +4938,7 @@ static int do_check(struct bpf_verifier_env *env)
48584938

48594939
if (*prev_dst_type == NOT_INIT) {
48604940
*prev_dst_type = dst_reg_type;
4861-
} else if (dst_reg_type != *prev_dst_type &&
4862-
(dst_reg_type == PTR_TO_CTX ||
4863-
*prev_dst_type == PTR_TO_CTX)) {
4941+
} else if (reg_type_mismatch(dst_reg_type, *prev_dst_type)) {
48644942
verbose(env, "same insn cannot be used with different pointers\n");
48654943
return -EINVAL;
48664944
}
@@ -5286,8 +5364,10 @@ static void sanitize_dead_code(struct bpf_verifier_env *env)
52865364
}
52875365
}
52885366

5289-
/* convert load instructions that access fields of 'struct __sk_buff'
5290-
* into sequence of instructions that access fields of 'struct sk_buff'
5367+
/* convert load instructions that access fields of a context type into a
5368+
* sequence of instructions that access fields of the underlying structure:
5369+
* struct __sk_buff -> struct sk_buff
5370+
* struct bpf_sock_ops -> struct sock
52915371
*/
52925372
static int convert_ctx_accesses(struct bpf_verifier_env *env)
52935373
{
@@ -5316,12 +5396,14 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
53165396
}
53175397
}
53185398

5319-
if (!ops->convert_ctx_access || bpf_prog_is_dev_bound(env->prog->aux))
5399+
if (bpf_prog_is_dev_bound(env->prog->aux))
53205400
return 0;
53215401

53225402
insn = env->prog->insnsi + delta;
53235403

53245404
for (i = 0; i < insn_cnt; i++, insn++) {
5405+
bpf_convert_ctx_access_t convert_ctx_access;
5406+
53255407
if (insn->code == (BPF_LDX | BPF_MEM | BPF_B) ||
53265408
insn->code == (BPF_LDX | BPF_MEM | BPF_H) ||
53275409
insn->code == (BPF_LDX | BPF_MEM | BPF_W) ||
@@ -5363,8 +5445,18 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
53635445
continue;
53645446
}
53655447

5366-
if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX)
5448+
switch (env->insn_aux_data[i + delta].ptr_type) {
5449+
case PTR_TO_CTX:
5450+
if (!ops->convert_ctx_access)
5451+
continue;
5452+
convert_ctx_access = ops->convert_ctx_access;
5453+
break;
5454+
case PTR_TO_SOCKET:
5455+
convert_ctx_access = bpf_sock_convert_ctx_access;
5456+
break;
5457+
default:
53675458
continue;
5459+
}
53685460

53695461
ctx_field_size = env->insn_aux_data[i + delta].ctx_field_size;
53705462
size = BPF_LDST_BYTES(insn);
@@ -5396,8 +5488,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
53965488
}
53975489

53985490
target_size = 0;
5399-
cnt = ops->convert_ctx_access(type, insn, insn_buf, env->prog,
5400-
&target_size);
5491+
cnt = convert_ctx_access(type, insn, insn_buf, env->prog,
5492+
&target_size);
54015493
if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf) ||
54025494
(ctx_field_size && !target_size)) {
54035495
verbose(env, "bpf verifier is misconfigured\n");

net/core/filter.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5394,23 +5394,29 @@ static bool __sock_filter_check_size(int off, int size,
53945394
return size == size_default;
53955395
}
53965396

5397-
static bool sock_filter_is_valid_access(int off, int size,
5398-
enum bpf_access_type type,
5399-
const struct bpf_prog *prog,
5400-
struct bpf_insn_access_aux *info)
5397+
bool bpf_sock_is_valid_access(int off, int size, enum bpf_access_type type,
5398+
struct bpf_insn_access_aux *info)
54015399
{
54025400
if (off < 0 || off >= sizeof(struct bpf_sock))
54035401
return false;
54045402
if (off % size != 0)
54055403
return false;
5406-
if (!__sock_filter_check_attach_type(off, type,
5407-
prog->expected_attach_type))
5408-
return false;
54095404
if (!__sock_filter_check_size(off, size, info))
54105405
return false;
54115406
return true;
54125407
}
54135408

5409+
static bool sock_filter_is_valid_access(int off, int size,
5410+
enum bpf_access_type type,
5411+
const struct bpf_prog *prog,
5412+
struct bpf_insn_access_aux *info)
5413+
{
5414+
if (!bpf_sock_is_valid_access(off, size, type, info))
5415+
return false;
5416+
return __sock_filter_check_attach_type(off, type,
5417+
prog->expected_attach_type);
5418+
}
5419+
54145420
static int bpf_unclone_prologue(struct bpf_insn *insn_buf, bool direct_write,
54155421
const struct bpf_prog *prog, int drop_verdict)
54165422
{
@@ -6122,10 +6128,10 @@ static u32 bpf_convert_ctx_access(enum bpf_access_type type,
61226128
return insn - insn_buf;
61236129
}
61246130

6125-
static u32 sock_filter_convert_ctx_access(enum bpf_access_type type,
6126-
const struct bpf_insn *si,
6127-
struct bpf_insn *insn_buf,
6128-
struct bpf_prog *prog, u32 *target_size)
6131+
u32 bpf_sock_convert_ctx_access(enum bpf_access_type type,
6132+
const struct bpf_insn *si,
6133+
struct bpf_insn *insn_buf,
6134+
struct bpf_prog *prog, u32 *target_size)
61296135
{
61306136
struct bpf_insn *insn = insn_buf;
61316137
int off;
@@ -7037,7 +7043,7 @@ const struct bpf_prog_ops lwt_seg6local_prog_ops = {
70377043
const struct bpf_verifier_ops cg_sock_verifier_ops = {
70387044
.get_func_proto = sock_filter_func_proto,
70397045
.is_valid_access = sock_filter_is_valid_access,
7040-
.convert_ctx_access = sock_filter_convert_ctx_access,
7046+
.convert_ctx_access = bpf_sock_convert_ctx_access,
70417047
};
70427048

70437049
const struct bpf_prog_ops cg_sock_prog_ops = {

0 commit comments

Comments
 (0)