Skip to content

Commit 7e4b23a

Browse files
committed
selftests/bpf: Add test to verify tailcall and freplace restrictions
JIRA: https://issues.redhat.com/browse/RHEL-85485 Conflicts: context change due to upstream commit 711df09 ("selftests/bpf: Add tests for tail calls with locks and refs") backported out-of-order. commit 021611d Author: Leon Hwang <leon.hwang@linux.dev> Date: Tue Oct 15 23:02:07 2024 +0800 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 <eddyz87@gmail.com> Signed-off-by: Leon Hwang <leon.hwang@linux.dev> Link: https://lore.kernel.org/r/20241015150207.70264-3-leon.hwang@linux.dev Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Viktor Malik <vmalik@redhat.com>
1 parent 9f8f1bb commit 7e4b23a

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
@@ -1502,16 +1502,16 @@ static void test_tailcall_bpf2bpf_hierarchy_3(void)
15021502
RUN_TESTS(tailcall_bpf2bpf_hierarchy3);
15031503
}
15041504

1505-
/* test_tailcall_freplace checks that the attached freplace prog is OK to
1506-
* update the prog_array map.
1505+
/* test_tailcall_freplace checks that the freplace prog fails to update the
1506+
* prog_array map, no matter whether the freplace prog attaches to its target.
15071507
*/
15081508
static void test_tailcall_freplace(void)
15091509
{
15101510
struct tailcall_freplace *freplace_skel = NULL;
15111511
struct bpf_link *freplace_link = NULL;
15121512
struct bpf_program *freplace_prog;
15131513
struct tc_bpf2bpf *tc_skel = NULL;
1514-
int prog_fd, map_fd;
1514+
int prog_fd, tc_prog_fd, map_fd;
15151515
char buff[128] = {};
15161516
int err, key;
15171517

@@ -1529,37 +1529,127 @@ static void test_tailcall_freplace(void)
15291529
if (!ASSERT_OK_PTR(tc_skel, "tc_bpf2bpf__open_and_load"))
15301530
goto out;
15311531

1532-
prog_fd = bpf_program__fd(tc_skel->progs.entry_tc);
1532+
tc_prog_fd = bpf_program__fd(tc_skel->progs.entry_tc);
15331533
freplace_prog = freplace_skel->progs.entry_freplace;
1534-
err = bpf_program__set_attach_target(freplace_prog, prog_fd, "subprog");
1534+
err = bpf_program__set_attach_target(freplace_prog, tc_prog_fd,
1535+
"subprog_tc");
15351536
if (!ASSERT_OK(err, "set_attach_target"))
15361537
goto out;
15371538

15381539
err = tailcall_freplace__load(freplace_skel);
15391540
if (!ASSERT_OK(err, "tailcall_freplace__load"))
15401541
goto out;
15411542

1542-
freplace_link = bpf_program__attach_freplace(freplace_prog, prog_fd,
1543-
"subprog");
1543+
map_fd = bpf_map__fd(freplace_skel->maps.jmp_table);
1544+
prog_fd = bpf_program__fd(freplace_prog);
1545+
key = 0;
1546+
err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY);
1547+
ASSERT_ERR(err, "update jmp_table failure");
1548+
1549+
freplace_link = bpf_program__attach_freplace(freplace_prog, tc_prog_fd,
1550+
"subprog_tc");
15441551
if (!ASSERT_OK_PTR(freplace_link, "attach_freplace"))
15451552
goto out;
15461553

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

1554-
prog_fd = bpf_program__fd(tc_skel->progs.entry_tc);
1555-
err = bpf_prog_test_run_opts(prog_fd, &topts);
1556-
ASSERT_OK(err, "test_run");
1557-
ASSERT_EQ(topts.retval, 34, "test_run retval");
1619+
err = bpf_map_delete_elem(map_fd, &key);
1620+
if (!ASSERT_OK(err, "delete_elem from jmp_table"))
1621+
goto out;
1622+
1623+
/* Fail to attach a tail callee prog with freplace prog. */
1624+
1625+
err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY);
1626+
if (!ASSERT_OK(err, "update jmp_table"))
1627+
goto out;
1628+
1629+
freplace_link = bpf_program__attach_freplace(freplace_skel->progs.entry_freplace,
1630+
prog_fd, "subprog_tc");
1631+
if (!ASSERT_ERR_PTR(freplace_link, "attach_freplace failure"))
1632+
goto out;
1633+
1634+
err = bpf_map_delete_elem(map_fd, &key);
1635+
if (!ASSERT_OK(err, "delete_elem from jmp_table"))
1636+
goto out;
1637+
1638+
/* Fail to update an extended prog to prog_array map. */
1639+
1640+
freplace_link = bpf_program__attach_freplace(freplace_skel->progs.entry_freplace,
1641+
prog_fd, "subprog_tc");
1642+
if (!ASSERT_OK_PTR(freplace_link, "attach_freplace"))
1643+
goto out;
1644+
1645+
err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY);
1646+
if (!ASSERT_ERR(err, "update jmp_table failure"))
1647+
goto out;
15581648

15591649
out:
15601650
bpf_link__destroy(freplace_link);
1561-
tc_bpf2bpf__destroy(tc_skel);
15621651
tailcall_freplace__destroy(freplace_skel);
1652+
tc_bpf2bpf__destroy(tc_skel);
15631653
}
15641654

15651655
void test_tailcalls(void)
@@ -1612,6 +1702,8 @@ void test_tailcalls(void)
16121702
test_tailcall_bpf2bpf_hierarchy_3();
16131703
if (test__start_subtest("tailcall_freplace"))
16141704
test_tailcall_freplace();
1705+
if (test__start_subtest("tailcall_bpf2bpf_freplace"))
1706+
test_tailcall_bpf2bpf_freplace();
16151707
if (test__start_subtest("tailcall_failure"))
16161708
test_tailcall_failure();
16171709
}

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)