Skip to content

Commit 9fd29c0

Browse files
yonghong-songdavem330
authored andcommitted
bpf: improve verifier ARG_CONST_SIZE_OR_ZERO semantics
For helpers, the argument type ARG_CONST_SIZE_OR_ZERO permits the access size to be 0 when accessing the previous argument (arg). Right now, it requires the arg needs to be NULL when size passed is 0 or could be 0. It also requires a non-NULL arg when the size is proved to be non-0. This patch changes verifier ARG_CONST_SIZE_OR_ZERO behavior such that for size-0 or possible size-0, it is not required the arg equal to NULL. There are a couple of reasons for this semantics change, and all of them intends to simplify user bpf programs which may improve user experience and/or increase chances of verifier acceptance. Together with the next patch which changes bpf_probe_read arg2 type from ARG_CONST_SIZE to ARG_CONST_SIZE_OR_ZERO, the following two examples, which fail the verifier currently, are able to get verifier acceptance. Example 1: unsigned long len = pend - pstart; len = len > MAX_PAYLOAD_LEN ? MAX_PAYLOAD_LEN : len; len &= MAX_PAYLOAD_LEN; bpf_probe_read(data->payload, len, pstart); It does not have test for "len > 0" and it failed the verifier. Users may not be aware that they have to add this test. Converting the bpf_probe_read helper to have ARG_CONST_SIZE_OR_ZERO helps the above code get verifier acceptance. Example 2: Here is one example where llvm "messed up" the code and the verifier fails. ...... unsigned long len = pend - pstart; if (len > 0 && len <= MAX_PAYLOAD_LEN) bpf_probe_read(data->payload, len, pstart); ...... The compiler generates the following code and verifier fails: ...... 39: (79) r2 = *(u64 *)(r10 -16) 40: (1f) r2 -= r8 41: (bf) r1 = r2 42: (07) r1 += -1 43: (25) if r1 > 0xffe goto pc+3 R0=inv(id=0) R1=inv(id=0,umax_value=4094,var_off=(0x0; 0xfff)) R2=inv(id=0) R6=map_value(id=0,off=0,ks=4,vs=4095,imm=0) R7=inv(id=0) R8=inv(id=0) R9=inv0 R10=fp0 44: (bf) r1 = r6 45: (bf) r3 = r8 46: (85) call bpf_probe_read#45 R2 min value is negative, either use unsigned or 'var &= const' ...... The compiler optimization is correct. If r1 = 0, r1 - 1 = 0xffffffffffffffff > 0xffe. If r1 != 0, r1 - 1 will not wrap. r1 > 0xffe at insn torvalds#43 can actually capture both "r1 > 0" and "len <= MAX_PAYLOAD_LEN". This however causes an issue in verifier as the value range of arg2 "r2" does not properly get refined and lead to verification failure. Relaxing bpf_prog_read arg2 from ARG_CONST_SIZE to ARG_CONST_SIZE_OR_ZERO allows the following simplied code: unsigned long len = pend - pstart; if (len <= MAX_PAYLOAD_LEN) bpf_probe_read(data->payload, len, pstart); The llvm compiler will generate less complex code and the verifier is able to verify that the program is okay. Signed-off-by: Yonghong Song <yhs@fb.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 3a9b76f commit 9fd29c0

File tree

1 file changed

+24
-16
lines changed

1 file changed

+24
-16
lines changed

kernel/bpf/verifier.c

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -799,12 +799,13 @@ static int check_stack_read(struct bpf_verifier_env *env,
799799

800800
/* check read/write into map element returned by bpf_map_lookup_elem() */
801801
static int __check_map_access(struct bpf_verifier_env *env, u32 regno, int off,
802-
int size)
802+
int size, bool zero_size_allowed)
803803
{
804804
struct bpf_reg_state *regs = cur_regs(env);
805805
struct bpf_map *map = regs[regno].map_ptr;
806806

807-
if (off < 0 || size <= 0 || off + size > map->value_size) {
807+
if (off < 0 || size < 0 || (size == 0 && !zero_size_allowed) ||
808+
off + size > map->value_size) {
808809
verbose(env, "invalid access to map value, value_size=%d off=%d size=%d\n",
809810
map->value_size, off, size);
810811
return -EACCES;
@@ -814,7 +815,7 @@ static int __check_map_access(struct bpf_verifier_env *env, u32 regno, int off,
814815

815816
/* check read/write into a map element with possible variable offset */
816817
static int check_map_access(struct bpf_verifier_env *env, u32 regno,
817-
int off, int size)
818+
int off, int size, bool zero_size_allowed)
818819
{
819820
struct bpf_verifier_state *state = env->cur_state;
820821
struct bpf_reg_state *reg = &state->regs[regno];
@@ -837,7 +838,8 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno,
837838
regno);
838839
return -EACCES;
839840
}
840-
err = __check_map_access(env, regno, reg->smin_value + off, size);
841+
err = __check_map_access(env, regno, reg->smin_value + off, size,
842+
zero_size_allowed);
841843
if (err) {
842844
verbose(env, "R%d min value is outside of the array range\n",
843845
regno);
@@ -853,7 +855,8 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno,
853855
regno);
854856
return -EACCES;
855857
}
856-
err = __check_map_access(env, regno, reg->umax_value + off, size);
858+
err = __check_map_access(env, regno, reg->umax_value + off, size,
859+
zero_size_allowed);
857860
if (err)
858861
verbose(env, "R%d max value is outside of the array range\n",
859862
regno);
@@ -889,12 +892,13 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
889892
}
890893

891894
static int __check_packet_access(struct bpf_verifier_env *env, u32 regno,
892-
int off, int size)
895+
int off, int size, bool zero_size_allowed)
893896
{
894897
struct bpf_reg_state *regs = cur_regs(env);
895898
struct bpf_reg_state *reg = &regs[regno];
896899

897-
if (off < 0 || size <= 0 || (u64)off + size > reg->range) {
900+
if (off < 0 || size < 0 || (size == 0 && !zero_size_allowed) ||
901+
(u64)off + size > reg->range) {
898902
verbose(env, "invalid access to packet, off=%d size=%d, R%d(id=%d,off=%d,r=%d)\n",
899903
off, size, regno, reg->id, reg->off, reg->range);
900904
return -EACCES;
@@ -903,7 +907,7 @@ static int __check_packet_access(struct bpf_verifier_env *env, u32 regno,
903907
}
904908

905909
static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off,
906-
int size)
910+
int size, bool zero_size_allowed)
907911
{
908912
struct bpf_reg_state *regs = cur_regs(env);
909913
struct bpf_reg_state *reg = &regs[regno];
@@ -922,7 +926,7 @@ static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off,
922926
regno);
923927
return -EACCES;
924928
}
925-
err = __check_packet_access(env, regno, off, size);
929+
err = __check_packet_access(env, regno, off, size, zero_size_allowed);
926930
if (err) {
927931
verbose(env, "R%d offset is outside of the packet\n", regno);
928932
return err;
@@ -1097,7 +1101,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
10971101
return -EACCES;
10981102
}
10991103

1100-
err = check_map_access(env, regno, off, size);
1104+
err = check_map_access(env, regno, off, size, false);
11011105
if (!err && t == BPF_READ && value_regno >= 0)
11021106
mark_reg_unknown(env, regs, value_regno);
11031107

@@ -1184,7 +1188,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
11841188
value_regno);
11851189
return -EACCES;
11861190
}
1187-
err = check_packet_access(env, regno, off, size);
1191+
err = check_packet_access(env, regno, off, size, false);
11881192
if (!err && t == BPF_READ && value_regno >= 0)
11891193
mark_reg_unknown(env, regs, value_regno);
11901194
} else {
@@ -1281,7 +1285,7 @@ static int check_stack_boundary(struct bpf_verifier_env *env, int regno,
12811285
}
12821286
off = regs[regno].off + regs[regno].var_off.value;
12831287
if (off >= 0 || off < -MAX_BPF_STACK || off + access_size > 0 ||
1284-
access_size <= 0) {
1288+
access_size < 0 || (access_size == 0 && !zero_size_allowed)) {
12851289
verbose(env, "invalid stack type R%d off=%d access_size=%d\n",
12861290
regno, off, access_size);
12871291
return -EACCES;
@@ -1319,9 +1323,11 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
13191323
switch (reg->type) {
13201324
case PTR_TO_PACKET:
13211325
case PTR_TO_PACKET_META:
1322-
return check_packet_access(env, regno, reg->off, access_size);
1326+
return check_packet_access(env, regno, reg->off, access_size,
1327+
zero_size_allowed);
13231328
case PTR_TO_MAP_VALUE:
1324-
return check_map_access(env, regno, reg->off, access_size);
1329+
return check_map_access(env, regno, reg->off, access_size,
1330+
zero_size_allowed);
13251331
default: /* scalar_value|ptr_to_stack or invalid ptr */
13261332
return check_stack_boundary(env, regno, access_size,
13271333
zero_size_allowed, meta);
@@ -1415,7 +1421,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
14151421
}
14161422
if (type_is_pkt_pointer(type))
14171423
err = check_packet_access(env, regno, reg->off,
1418-
meta->map_ptr->key_size);
1424+
meta->map_ptr->key_size,
1425+
false);
14191426
else
14201427
err = check_stack_boundary(env, regno,
14211428
meta->map_ptr->key_size,
@@ -1431,7 +1438,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
14311438
}
14321439
if (type_is_pkt_pointer(type))
14331440
err = check_packet_access(env, regno, reg->off,
1434-
meta->map_ptr->value_size);
1441+
meta->map_ptr->value_size,
1442+
false);
14351443
else
14361444
err = check_stack_boundary(env, regno,
14371445
meta->map_ptr->value_size,

0 commit comments

Comments
 (0)