Skip to content

Commit 9013341

Browse files
borkmannAlexei Starovoitov
authored andcommitted
bpf, verifier: detect misconfigured mem, size argument pair
I've seen two patch proposals now for helper additions that used ARG_PTR_TO_MEM or similar in reg_X but no corresponding ARG_CONST_SIZE in reg_X+1. Verifier won't complain in such case, but it will omit verifying the memory passed to the helper thus ending up badly. Detect such buggy helper function signature and bail out during verification rather than finding them through review. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 417f1d9 commit 9013341

File tree

1 file changed

+55
-24
lines changed

1 file changed

+55
-24
lines changed

kernel/bpf/verifier.c

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1837,6 +1837,19 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
18371837
}
18381838
}
18391839

1840+
static bool arg_type_is_mem_ptr(enum bpf_arg_type type)
1841+
{
1842+
return type == ARG_PTR_TO_MEM ||
1843+
type == ARG_PTR_TO_MEM_OR_NULL ||
1844+
type == ARG_PTR_TO_UNINIT_MEM;
1845+
}
1846+
1847+
static bool arg_type_is_mem_size(enum bpf_arg_type type)
1848+
{
1849+
return type == ARG_CONST_SIZE ||
1850+
type == ARG_CONST_SIZE_OR_ZERO;
1851+
}
1852+
18401853
static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
18411854
enum bpf_arg_type arg_type,
18421855
struct bpf_call_arg_meta *meta)
@@ -1886,9 +1899,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
18861899
expected_type = PTR_TO_CTX;
18871900
if (type != expected_type)
18881901
goto err_type;
1889-
} else if (arg_type == ARG_PTR_TO_MEM ||
1890-
arg_type == ARG_PTR_TO_MEM_OR_NULL ||
1891-
arg_type == ARG_PTR_TO_UNINIT_MEM) {
1902+
} else if (arg_type_is_mem_ptr(arg_type)) {
18921903
expected_type = PTR_TO_STACK;
18931904
/* One exception here. In case function allows for NULL to be
18941905
* passed in as argument, it's a SCALAR_VALUE type. Final test
@@ -1949,25 +1960,12 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
19491960
err = check_stack_boundary(env, regno,
19501961
meta->map_ptr->value_size,
19511962
false, NULL);
1952-
} else if (arg_type == ARG_CONST_SIZE ||
1953-
arg_type == ARG_CONST_SIZE_OR_ZERO) {
1963+
} else if (arg_type_is_mem_size(arg_type)) {
19541964
bool zero_size_allowed = (arg_type == ARG_CONST_SIZE_OR_ZERO);
19551965

1956-
/* bpf_xxx(..., buf, len) call will access 'len' bytes
1957-
* from stack pointer 'buf'. Check it
1958-
* note: regno == len, regno - 1 == buf
1959-
*/
1960-
if (regno == 0) {
1961-
/* kernel subsystem misconfigured verifier */
1962-
verbose(env,
1963-
"ARG_CONST_SIZE cannot be first argument\n");
1964-
return -EACCES;
1965-
}
1966-
19671966
/* The register is SCALAR_VALUE; the access check
19681967
* happens using its boundaries.
19691968
*/
1970-
19711969
if (!tnum_is_const(reg->var_off))
19721970
/* For unprivileged variable accesses, disable raw
19731971
* mode so that the program is required to
@@ -2111,7 +2109,7 @@ static int check_map_func_compatibility(struct bpf_verifier_env *env,
21112109
return -EINVAL;
21122110
}
21132111

2114-
static int check_raw_mode(const struct bpf_func_proto *fn)
2112+
static bool check_raw_mode_ok(const struct bpf_func_proto *fn)
21152113
{
21162114
int count = 0;
21172115

@@ -2126,7 +2124,44 @@ static int check_raw_mode(const struct bpf_func_proto *fn)
21262124
if (fn->arg5_type == ARG_PTR_TO_UNINIT_MEM)
21272125
count++;
21282126

2129-
return count > 1 ? -EINVAL : 0;
2127+
/* We only support one arg being in raw mode at the moment,
2128+
* which is sufficient for the helper functions we have
2129+
* right now.
2130+
*/
2131+
return count <= 1;
2132+
}
2133+
2134+
static bool check_args_pair_invalid(enum bpf_arg_type arg_curr,
2135+
enum bpf_arg_type arg_next)
2136+
{
2137+
return (arg_type_is_mem_ptr(arg_curr) &&
2138+
!arg_type_is_mem_size(arg_next)) ||
2139+
(!arg_type_is_mem_ptr(arg_curr) &&
2140+
arg_type_is_mem_size(arg_next));
2141+
}
2142+
2143+
static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
2144+
{
2145+
/* bpf_xxx(..., buf, len) call will access 'len'
2146+
* bytes from memory 'buf'. Both arg types need
2147+
* to be paired, so make sure there's no buggy
2148+
* helper function specification.
2149+
*/
2150+
if (arg_type_is_mem_size(fn->arg1_type) ||
2151+
arg_type_is_mem_ptr(fn->arg5_type) ||
2152+
check_args_pair_invalid(fn->arg1_type, fn->arg2_type) ||
2153+
check_args_pair_invalid(fn->arg2_type, fn->arg3_type) ||
2154+
check_args_pair_invalid(fn->arg3_type, fn->arg4_type) ||
2155+
check_args_pair_invalid(fn->arg4_type, fn->arg5_type))
2156+
return false;
2157+
2158+
return true;
2159+
}
2160+
2161+
static int check_func_proto(const struct bpf_func_proto *fn)
2162+
{
2163+
return check_raw_mode_ok(fn) &&
2164+
check_arg_pair_ok(fn) ? 0 : -EINVAL;
21302165
}
21312166

21322167
/* Packet data might have moved, any old PTR_TO_PACKET[_META,_END]
@@ -2282,7 +2317,6 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
22822317

22832318
if (env->ops->get_func_proto)
22842319
fn = env->ops->get_func_proto(func_id);
2285-
22862320
if (!fn) {
22872321
verbose(env, "unknown func %s#%d\n", func_id_name(func_id),
22882322
func_id);
@@ -2306,10 +2340,7 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
23062340
memset(&meta, 0, sizeof(meta));
23072341
meta.pkt_access = fn->pkt_access;
23082342

2309-
/* We only support one arg being in raw mode at the moment, which
2310-
* is sufficient for the helper functions we have right now.
2311-
*/
2312-
err = check_raw_mode(fn);
2343+
err = check_func_proto(fn);
23132344
if (err) {
23142345
verbose(env, "kernel subsystem misconfigured func %s#%d\n",
23152346
func_id_name(func_id), func_id);

0 commit comments

Comments
 (0)