Skip to content

Commit 021611d

Browse files
AsphalttAlexei Starovoitov
authored and
Alexei Starovoitov
committed
selftests/bpf: Add test to verify tailcall and freplace restrictions
Add a test case to ensure that attaching a tail callee program with an freplace program fails, and that updating an extended program to a prog_array map is also prohibited. This test is designed to prevent the potential infinite loop issue caused by the combination of tail calls and freplace, ensuring the correct behavior and stability of the system. Additionally, fix the broken tailcalls/tailcall_freplace selftest because an extension prog should not be tailcalled. cd tools/testing/selftests/bpf; ./test_progs -t tailcalls 337/25 tailcalls/tailcall_freplace:OK 337/26 tailcalls/tailcall_bpf2bpf_freplace:OK 337 tailcalls:OK Summary: 1/26 PASSED, 0 SKIPPED, 0 FAILED Acked-by: Eduard Zingerman <[email protected]> Signed-off-by: Leon Hwang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent d6083f0 commit 021611d

File tree

2 files changed

+109
-16
lines changed

2 files changed

+109
-16
lines changed

tools/testing/selftests/bpf/prog_tests/tailcalls.c

Lines changed: 106 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,16 +1496,16 @@ static void test_tailcall_bpf2bpf_hierarchy_3(void)
14961496
RUN_TESTS(tailcall_bpf2bpf_hierarchy3);
14971497
}
14981498

1499-
/* test_tailcall_freplace checks that the attached freplace prog is OK to
1500-
* update the prog_array map.
1499+
/* test_tailcall_freplace checks that the freplace prog fails to update the
1500+
* prog_array map, no matter whether the freplace prog attaches to its target.
15011501
*/
15021502
static void test_tailcall_freplace(void)
15031503
{
15041504
struct tailcall_freplace *freplace_skel = NULL;
15051505
struct bpf_link *freplace_link = NULL;
15061506
struct bpf_program *freplace_prog;
15071507
struct tc_bpf2bpf *tc_skel = NULL;
1508-
int prog_fd, map_fd;
1508+
int prog_fd, tc_prog_fd, map_fd;
15091509
char buff[128] = {};
15101510
int err, key;
15111511

@@ -1523,37 +1523,127 @@ static void test_tailcall_freplace(void)
15231523
if (!ASSERT_OK_PTR(tc_skel, "tc_bpf2bpf__open_and_load"))
15241524
goto out;
15251525

1526-
prog_fd = bpf_program__fd(tc_skel->progs.entry_tc);
1526+
tc_prog_fd = bpf_program__fd(tc_skel->progs.entry_tc);
15271527
freplace_prog = freplace_skel->progs.entry_freplace;
1528-
err = bpf_program__set_attach_target(freplace_prog, prog_fd, "subprog");
1528+
err = bpf_program__set_attach_target(freplace_prog, tc_prog_fd,
1529+
"subprog_tc");
15291530
if (!ASSERT_OK(err, "set_attach_target"))
15301531
goto out;
15311532

15321533
err = tailcall_freplace__load(freplace_skel);
15331534
if (!ASSERT_OK(err, "tailcall_freplace__load"))
15341535
goto out;
15351536

1536-
freplace_link = bpf_program__attach_freplace(freplace_prog, prog_fd,
1537-
"subprog");
1537+
map_fd = bpf_map__fd(freplace_skel->maps.jmp_table);
1538+
prog_fd = bpf_program__fd(freplace_prog);
1539+
key = 0;
1540+
err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY);
1541+
ASSERT_ERR(err, "update jmp_table failure");
1542+
1543+
freplace_link = bpf_program__attach_freplace(freplace_prog, tc_prog_fd,
1544+
"subprog_tc");
15381545
if (!ASSERT_OK_PTR(freplace_link, "attach_freplace"))
15391546
goto out;
15401547

1541-
map_fd = bpf_map__fd(freplace_skel->maps.jmp_table);
1542-
prog_fd = bpf_program__fd(freplace_prog);
1548+
err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY);
1549+
ASSERT_ERR(err, "update jmp_table failure");
1550+
1551+
out:
1552+
bpf_link__destroy(freplace_link);
1553+
tailcall_freplace__destroy(freplace_skel);
1554+
tc_bpf2bpf__destroy(tc_skel);
1555+
}
1556+
1557+
/* test_tailcall_bpf2bpf_freplace checks the failure that fails to attach a tail
1558+
* callee prog with freplace prog or fails to update an extended prog to
1559+
* prog_array map.
1560+
*/
1561+
static void test_tailcall_bpf2bpf_freplace(void)
1562+
{
1563+
struct tailcall_freplace *freplace_skel = NULL;
1564+
struct bpf_link *freplace_link = NULL;
1565+
struct tc_bpf2bpf *tc_skel = NULL;
1566+
char buff[128] = {};
1567+
int prog_fd, map_fd;
1568+
int err, key;
1569+
1570+
LIBBPF_OPTS(bpf_test_run_opts, topts,
1571+
.data_in = buff,
1572+
.data_size_in = sizeof(buff),
1573+
.repeat = 1,
1574+
);
1575+
1576+
tc_skel = tc_bpf2bpf__open_and_load();
1577+
if (!ASSERT_OK_PTR(tc_skel, "tc_bpf2bpf__open_and_load"))
1578+
goto out;
1579+
1580+
prog_fd = bpf_program__fd(tc_skel->progs.entry_tc);
1581+
freplace_skel = tailcall_freplace__open();
1582+
if (!ASSERT_OK_PTR(freplace_skel, "tailcall_freplace__open"))
1583+
goto out;
1584+
1585+
err = bpf_program__set_attach_target(freplace_skel->progs.entry_freplace,
1586+
prog_fd, "subprog_tc");
1587+
if (!ASSERT_OK(err, "set_attach_target"))
1588+
goto out;
1589+
1590+
err = tailcall_freplace__load(freplace_skel);
1591+
if (!ASSERT_OK(err, "tailcall_freplace__load"))
1592+
goto out;
1593+
1594+
/* OK to attach then detach freplace prog. */
1595+
1596+
freplace_link = bpf_program__attach_freplace(freplace_skel->progs.entry_freplace,
1597+
prog_fd, "subprog_tc");
1598+
if (!ASSERT_OK_PTR(freplace_link, "attach_freplace"))
1599+
goto out;
1600+
1601+
err = bpf_link__destroy(freplace_link);
1602+
if (!ASSERT_OK(err, "destroy link"))
1603+
goto out;
1604+
1605+
/* OK to update prog_array map then delete element from the map. */
1606+
15431607
key = 0;
1608+
map_fd = bpf_map__fd(freplace_skel->maps.jmp_table);
15441609
err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY);
15451610
if (!ASSERT_OK(err, "update jmp_table"))
15461611
goto out;
15471612

1548-
prog_fd = bpf_program__fd(tc_skel->progs.entry_tc);
1549-
err = bpf_prog_test_run_opts(prog_fd, &topts);
1550-
ASSERT_OK(err, "test_run");
1551-
ASSERT_EQ(topts.retval, 34, "test_run retval");
1613+
err = bpf_map_delete_elem(map_fd, &key);
1614+
if (!ASSERT_OK(err, "delete_elem from jmp_table"))
1615+
goto out;
1616+
1617+
/* Fail to attach a tail callee prog with freplace prog. */
1618+
1619+
err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY);
1620+
if (!ASSERT_OK(err, "update jmp_table"))
1621+
goto out;
1622+
1623+
freplace_link = bpf_program__attach_freplace(freplace_skel->progs.entry_freplace,
1624+
prog_fd, "subprog_tc");
1625+
if (!ASSERT_ERR_PTR(freplace_link, "attach_freplace failure"))
1626+
goto out;
1627+
1628+
err = bpf_map_delete_elem(map_fd, &key);
1629+
if (!ASSERT_OK(err, "delete_elem from jmp_table"))
1630+
goto out;
1631+
1632+
/* Fail to update an extended prog to prog_array map. */
1633+
1634+
freplace_link = bpf_program__attach_freplace(freplace_skel->progs.entry_freplace,
1635+
prog_fd, "subprog_tc");
1636+
if (!ASSERT_OK_PTR(freplace_link, "attach_freplace"))
1637+
goto out;
1638+
1639+
err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY);
1640+
if (!ASSERT_ERR(err, "update jmp_table failure"))
1641+
goto out;
15521642

15531643
out:
15541644
bpf_link__destroy(freplace_link);
1555-
tc_bpf2bpf__destroy(tc_skel);
15561645
tailcall_freplace__destroy(freplace_skel);
1646+
tc_bpf2bpf__destroy(tc_skel);
15571647
}
15581648

15591649
void test_tailcalls(void)
@@ -1606,4 +1696,6 @@ void test_tailcalls(void)
16061696
test_tailcall_bpf2bpf_hierarchy_3();
16071697
if (test__start_subtest("tailcall_freplace"))
16081698
test_tailcall_freplace();
1699+
if (test__start_subtest("tailcall_bpf2bpf_freplace"))
1700+
test_tailcall_bpf2bpf_freplace();
16091701
}

tools/testing/selftests/bpf/progs/tc_bpf2bpf.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@
55
#include "bpf_misc.h"
66

77
__noinline
8-
int subprog(struct __sk_buff *skb)
8+
int subprog_tc(struct __sk_buff *skb)
99
{
1010
int ret = 1;
1111

12+
__sink(skb);
1213
__sink(ret);
1314
return ret;
1415
}
1516

1617
SEC("tc")
1718
int entry_tc(struct __sk_buff *skb)
1819
{
19-
return subprog(skb);
20+
return subprog_tc(skb);
2021
}
2122

2223
char __license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)