selftests/bpf: add test for bpf_msg_pop_data() overflow

Add a test in sockmap_basic.c that calls bpf_msg_pop_data() with a length
close to U32_MAX, which overflows the start + len bounds check. The sk_msg
program records the return value over a sendmsg and the test checks that
the call is rejected with -EINVAL.

Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Cc: Jiayuan Chen <jiayuan.chen@linux.dev>
Signed-off-by: Sechang Lim <rhkrqnwk98@gmail.com>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Link: https://lore.kernel.org/r/20260615021959.140010-7-jiayuan.chen@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Sechang Lim 2026-06-15 10:19:59 +08:00 committed by Alexei Starovoitov
parent a48802fb2c
commit 70b139d048
2 changed files with 75 additions and 0 deletions

View File

@ -14,6 +14,7 @@
#include "test_sockmap_pass_prog.skel.h"
#include "test_sockmap_drop_prog.skel.h"
#include "test_sockmap_change_tail.skel.h"
#include "test_sockmap_msg_pop_data.skel.h"
#include "bpf_iter_sockmap.skel.h"
#include "sockmap_helpers.h"
@ -666,6 +667,51 @@ static void test_sockmap_skb_verdict_change_tail(void)
test_sockmap_change_tail__destroy(skel);
}
static void test_sockmap_msg_verdict_pop_data(void)
{
struct test_sockmap_msg_pop_data *skel;
int err, map, verdict;
int c1 = -1, p1 = -1, sent;
int zero = 0;
char *buf;
const size_t len = 32 * 1024;
skel = test_sockmap_msg_pop_data__open_and_load();
if (!ASSERT_OK_PTR(skel, "open_and_load"))
return;
verdict = bpf_program__fd(skel->progs.prog_msg_pop_data);
map = bpf_map__fd(skel->maps.sock_map);
err = bpf_prog_attach(verdict, map, BPF_SK_MSG_VERDICT, 0);
if (!ASSERT_OK(err, "bpf_prog_attach"))
goto out;
err = create_pair(AF_INET, SOCK_STREAM, &c1, &p1);
if (!ASSERT_OK(err, "create_pair"))
goto out;
err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
if (!ASSERT_OK(err, "bpf_map_update_elem"))
goto out_close;
buf = calloc(len, 1);
if (!ASSERT_OK_PTR(buf, "calloc"))
goto out_close;
sent = xsend(c1, buf, len, 0);
ASSERT_EQ(sent, (ssize_t)len, "xsend");
ASSERT_EQ(skel->data->pop_data_ret, -EINVAL, "pop_data_rejects overflow");
free(buf);
out_close:
close(c1);
close(p1);
out:
test_sockmap_msg_pop_data__destroy(skel);
}
static void test_sockmap_skb_verdict_peek_helper(int map)
{
int err, c1, p1, zero = 0, sent, recvd, avail;
@ -1373,6 +1419,8 @@ void test_sockmap_basic(void)
test_sockmap_skb_verdict_fionread(false);
if (test__start_subtest("sockmap skb_verdict change tail"))
test_sockmap_skb_verdict_change_tail();
if (test__start_subtest("sockmap msg_verdict pop_data overflow"))
test_sockmap_msg_verdict_pop_data();
if (test__start_subtest("sockmap skb_verdict msg_f_peek"))
test_sockmap_skb_verdict_peek();
if (test__start_subtest("sockmap skb_verdict msg_f_peek with link"))

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
struct {
__uint(type, BPF_MAP_TYPE_SOCKMAP);
__uint(max_entries, 1);
__type(key, int);
__type(value, int);
} sock_map SEC(".maps");
#define POP_START 0x48a3
#define POP_LEN 0xfffffffd
long pop_data_ret = 1;
SEC("sk_msg")
int prog_msg_pop_data(struct sk_msg_md *msg)
{
if (msg->size <= POP_START)
return SK_PASS;
pop_data_ret = bpf_msg_pop_data(msg, POP_START, POP_LEN, 0);
return SK_PASS;
}
char _license[] SEC("license") = "GPL";