Skip to content

Commit 32556ce

Browse files
borkmannAlexei Starovoitov
authored andcommitted
bpf: Fix helper writes to read-only maps
Lonial found an issue that despite user- and BPF-side frozen BPF map (like in case of .rodata), it was still possible to write into it from a BPF program side through specific helpers having ARG_PTR_TO_{LONG,INT} as arguments. In check_func_arg() when the argument is as mentioned, the meta->raw_mode is never set. Later, check_helper_mem_access(), under the case of PTR_TO_MAP_VALUE as register base type, it assumes BPF_READ for the subsequent call to check_map_access_type() and given the BPF map is read-only it succeeds. The helpers really need to be annotated as ARG_PTR_TO_{LONG,INT} | MEM_UNINIT when results are written into them as opposed to read out of them. The latter indicates that it's okay to pass a pointer to uninitialized memory as the memory is written to anyway. However, ARG_PTR_TO_{LONG,INT} is a special case of ARG_PTR_TO_FIXED_SIZE_MEM just with additional alignment requirement. So it is better to just get rid of the ARG_PTR_TO_{LONG,INT} special cases altogether and reuse the fixed size memory types. For this, add MEM_ALIGNED to additionally ensure alignment given these helpers write directly into the args via *<ptr> = val. The .arg*_size has been initialized reflecting the actual sizeof(*<ptr>). MEM_ALIGNED can only be used in combination with MEM_FIXED_SIZE annotated argument types, since in !MEM_FIXED_SIZE cases the verifier does not know the buffer size a priori and therefore cannot blindly write *<ptr> = val. Fixes: 57c3bb7 ("bpf: Introduce ARG_PTR_TO_{INT,LONG} arg types") Reported-by: Lonial Con <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Acked-by: Shung-Hsi Yu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 7d71f59 commit 32556ce

File tree

6 files changed

+24
-45
lines changed

6 files changed

+24
-45
lines changed

include/linux/bpf.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,11 @@ enum bpf_type_flag {
695695
/* DYNPTR points to xdp_buff */
696696
DYNPTR_TYPE_XDP = BIT(16 + BPF_BASE_TYPE_BITS),
697697

698+
/* Memory must be aligned on some architectures, used in combination with
699+
* MEM_FIXED_SIZE.
700+
*/
701+
MEM_ALIGNED = BIT(17 + BPF_BASE_TYPE_BITS),
702+
698703
__BPF_TYPE_FLAG_MAX,
699704
__BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1,
700705
};
@@ -732,8 +737,6 @@ enum bpf_arg_type {
732737
ARG_ANYTHING, /* any (initialized) argument is ok */
733738
ARG_PTR_TO_SPIN_LOCK, /* pointer to bpf_spin_lock */
734739
ARG_PTR_TO_SOCK_COMMON, /* pointer to sock_common */
735-
ARG_PTR_TO_INT, /* pointer to int */
736-
ARG_PTR_TO_LONG, /* pointer to long */
737740
ARG_PTR_TO_SOCKET, /* pointer to bpf_sock (fullsock) */
738741
ARG_PTR_TO_BTF_ID, /* pointer to in-kernel struct */
739742
ARG_PTR_TO_RINGBUF_MEM, /* pointer to dynamically reserved ringbuf memory */

kernel/bpf/helpers.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,8 @@ const struct bpf_func_proto bpf_strtol_proto = {
537537
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
538538
.arg2_type = ARG_CONST_SIZE,
539539
.arg3_type = ARG_ANYTHING,
540-
.arg4_type = ARG_PTR_TO_LONG,
540+
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
541+
.arg4_size = sizeof(s64),
541542
};
542543

543544
BPF_CALL_4(bpf_strtoul, const char *, buf, size_t, buf_len, u64, flags,
@@ -563,7 +564,8 @@ const struct bpf_func_proto bpf_strtoul_proto = {
563564
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
564565
.arg2_type = ARG_CONST_SIZE,
565566
.arg3_type = ARG_ANYTHING,
566-
.arg4_type = ARG_PTR_TO_LONG,
567+
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
568+
.arg4_size = sizeof(u64),
567569
};
568570

569571
BPF_CALL_3(bpf_strncmp, const char *, s1, u32, s1_sz, const char *, s2)

kernel/bpf/syscall.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5954,7 +5954,8 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
59545954
.arg1_type = ARG_PTR_TO_MEM,
59555955
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
59565956
.arg3_type = ARG_ANYTHING,
5957-
.arg4_type = ARG_PTR_TO_LONG,
5957+
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
5958+
.arg4_size = sizeof(u64),
59585959
};
59595960

59605961
static const struct bpf_func_proto *

kernel/bpf/verifier.c

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8301,16 +8301,6 @@ static bool arg_type_is_dynptr(enum bpf_arg_type type)
83018301
return base_type(type) == ARG_PTR_TO_DYNPTR;
83028302
}
83038303

8304-
static int int_ptr_type_to_size(enum bpf_arg_type type)
8305-
{
8306-
if (type == ARG_PTR_TO_INT)
8307-
return sizeof(u32);
8308-
else if (type == ARG_PTR_TO_LONG)
8309-
return sizeof(u64);
8310-
8311-
return -EINVAL;
8312-
}
8313-
83148304
static int resolve_map_arg_type(struct bpf_verifier_env *env,
83158305
const struct bpf_call_arg_meta *meta,
83168306
enum bpf_arg_type *arg_type)
@@ -8383,16 +8373,6 @@ static const struct bpf_reg_types mem_types = {
83838373
},
83848374
};
83858375

8386-
static const struct bpf_reg_types int_ptr_types = {
8387-
.types = {
8388-
PTR_TO_STACK,
8389-
PTR_TO_PACKET,
8390-
PTR_TO_PACKET_META,
8391-
PTR_TO_MAP_KEY,
8392-
PTR_TO_MAP_VALUE,
8393-
},
8394-
};
8395-
83968376
static const struct bpf_reg_types spin_lock_types = {
83978377
.types = {
83988378
PTR_TO_MAP_VALUE,
@@ -8453,8 +8433,6 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
84538433
[ARG_PTR_TO_SPIN_LOCK] = &spin_lock_types,
84548434
[ARG_PTR_TO_MEM] = &mem_types,
84558435
[ARG_PTR_TO_RINGBUF_MEM] = &ringbuf_mem_types,
8456-
[ARG_PTR_TO_INT] = &int_ptr_types,
8457-
[ARG_PTR_TO_LONG] = &int_ptr_types,
84588436
[ARG_PTR_TO_PERCPU_BTF_ID] = &percpu_btf_ptr_types,
84598437
[ARG_PTR_TO_FUNC] = &func_ptr_types,
84608438
[ARG_PTR_TO_STACK] = &stack_ptr_types,
@@ -9017,9 +8995,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
90178995
*/
90188996
meta->raw_mode = arg_type & MEM_UNINIT;
90198997
if (arg_type & MEM_FIXED_SIZE) {
9020-
err = check_helper_mem_access(env, regno,
9021-
fn->arg_size[arg], false,
9022-
meta);
8998+
err = check_helper_mem_access(env, regno, fn->arg_size[arg], false, meta);
8999+
if (err)
9000+
return err;
9001+
if (arg_type & MEM_ALIGNED)
9002+
err = check_ptr_alignment(env, reg, 0, fn->arg_size[arg], true);
90239003
}
90249004
break;
90259005
case ARG_CONST_SIZE:
@@ -9044,17 +9024,6 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
90449024
if (err)
90459025
return err;
90469026
break;
9047-
case ARG_PTR_TO_INT:
9048-
case ARG_PTR_TO_LONG:
9049-
{
9050-
int size = int_ptr_type_to_size(arg_type);
9051-
9052-
err = check_helper_mem_access(env, regno, size, false, meta);
9053-
if (err)
9054-
return err;
9055-
err = check_ptr_alignment(env, reg, 0, size, true);
9056-
break;
9057-
}
90589027
case ARG_PTR_TO_CONST_STR:
90599028
{
90609029
err = check_reg_const_str(env, reg, regno);

kernel/trace/bpf_trace.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,7 +1202,8 @@ static const struct bpf_func_proto bpf_get_func_arg_proto = {
12021202
.ret_type = RET_INTEGER,
12031203
.arg1_type = ARG_PTR_TO_CTX,
12041204
.arg2_type = ARG_ANYTHING,
1205-
.arg3_type = ARG_PTR_TO_LONG,
1205+
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
1206+
.arg3_size = sizeof(u64),
12061207
};
12071208

12081209
BPF_CALL_2(get_func_ret, void *, ctx, u64 *, value)
@@ -1218,7 +1219,8 @@ static const struct bpf_func_proto bpf_get_func_ret_proto = {
12181219
.func = get_func_ret,
12191220
.ret_type = RET_INTEGER,
12201221
.arg1_type = ARG_PTR_TO_CTX,
1221-
.arg2_type = ARG_PTR_TO_LONG,
1222+
.arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
1223+
.arg2_size = sizeof(u64),
12221224
};
12231225

12241226
BPF_CALL_1(get_func_arg_cnt, void *, ctx)

net/core/filter.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6346,7 +6346,8 @@ static const struct bpf_func_proto bpf_skb_check_mtu_proto = {
63466346
.ret_type = RET_INTEGER,
63476347
.arg1_type = ARG_PTR_TO_CTX,
63486348
.arg2_type = ARG_ANYTHING,
6349-
.arg3_type = ARG_PTR_TO_INT,
6349+
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
6350+
.arg3_size = sizeof(u32),
63506351
.arg4_type = ARG_ANYTHING,
63516352
.arg5_type = ARG_ANYTHING,
63526353
};
@@ -6357,7 +6358,8 @@ static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {
63576358
.ret_type = RET_INTEGER,
63586359
.arg1_type = ARG_PTR_TO_CTX,
63596360
.arg2_type = ARG_ANYTHING,
6360-
.arg3_type = ARG_PTR_TO_INT,
6361+
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
6362+
.arg3_size = sizeof(u32),
63616363
.arg4_type = ARG_ANYTHING,
63626364
.arg5_type = ARG_ANYTHING,
63636365
};

0 commit comments

Comments
 (0)