1. The trusted VMA pointer can be null and must be checked before dereferencing. 2. Resources acquired via bpf_mm_get_task() must be released with bpf_task_release(). 3. Memory groups obtained through bpf_mm_get_mem_cgroup() must be released using bpf_put_mem_cgroup(). Signed-off-by: Yafang Shao --- .../selftests/bpf/prog_tests/thp_adjust.c | 7 +++++ .../bpf/progs/test_thp_adjust_trusted_vma.c | 27 +++++++++++++++++++ .../progs/test_thp_adjust_unreleased_memcg.c | 24 +++++++++++++++++ .../progs/test_thp_adjust_unreleased_task.c | 25 +++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/test_thp_adjust_trusted_vma.c create mode 100644 tools/testing/selftests/bpf/progs/test_thp_adjust_unreleased_memcg.c create mode 100644 tools/testing/selftests/bpf/progs/test_thp_adjust_unreleased_task.c diff --git a/tools/testing/selftests/bpf/prog_tests/thp_adjust.c b/tools/testing/selftests/bpf/prog_tests/thp_adjust.c index 6e65d7b0eb80..846679acaff2 100644 --- a/tools/testing/selftests/bpf/prog_tests/thp_adjust.c +++ b/tools/testing/selftests/bpf/prog_tests/thp_adjust.c @@ -11,6 +11,9 @@ #include #include "cgroup_helpers.h" #include "test_thp_adjust.skel.h" +#include "test_thp_adjust_trusted_vma.skel.h" +#include "test_thp_adjust_unreleased_task.skel.h" +#include "test_thp_adjust_unreleased_memcg.skel.h" #define LEN (16 * 1024 * 1024) /* 16MB */ #define THP_ENABLED_FILE "/sys/kernel/mm/transparent_hugepage/enabled" @@ -333,4 +336,8 @@ void test_thp_adjust(void) subtest_thp_policy_update(); thp_adjust_destroy(); + + RUN_TESTS(test_thp_adjust_trusted_vma); + RUN_TESTS(test_thp_adjust_unreleased_task); + RUN_TESTS(test_thp_adjust_unreleased_memcg); } diff --git a/tools/testing/selftests/bpf/progs/test_thp_adjust_trusted_vma.c b/tools/testing/selftests/bpf/progs/test_thp_adjust_trusted_vma.c new file mode 100644 index 000000000000..caa73bebefcf --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_thp_adjust_trusted_vma.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include +#include + +#include "bpf_misc.h" + +char _license[] SEC("license") = "GPL"; + +SEC("struct_ops/get_suggested_order") +__failure __msg("R1 invalid mem access 'trusted_ptr_or_null_'") +int BPF_PROG(thp_trusted_vma, struct mm_struct *mm, struct vm_area_struct *vma__nullable, + u64 vma_flags, u64 tva_flags, int orders) +{ + struct mem_cgroup *memcg = bpf_mm_get_mem_cgroup(vma__nullable->vm_mm); + + if (!memcg) + return 0; + + bpf_put_mem_cgroup(memcg); + return 1; +} +SEC(".struct_ops.link") +struct bpf_thp_ops thp_memcg_ops = { + .get_suggested_order = (void *)thp_trusted_vma, +}; diff --git a/tools/testing/selftests/bpf/progs/test_thp_adjust_unreleased_memcg.c b/tools/testing/selftests/bpf/progs/test_thp_adjust_unreleased_memcg.c new file mode 100644 index 000000000000..467befebb35f --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_thp_adjust_unreleased_memcg.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include +#include + +#include "bpf_misc.h" + +char _license[] SEC("license") = "GPL"; + +SEC("struct_ops/get_suggested_order") +__failure __msg("Unreleased reference") +int BPF_PROG(thp_unreleased_memcg, struct mm_struct *mm, struct vm_area_struct *vma__nullable, + u64 vma_flags, u64 tva_flags, int orders) +{ + struct mem_cgroup *memcg = bpf_mm_get_mem_cgroup(mm); + + /* The memcg should be released with bpf_put_mem_cgroup() */ + return memcg ? 0 : 1; +} +SEC(".struct_ops.link") +struct bpf_thp_ops thp_memcg_ops = { + .get_suggested_order = (void *)thp_unreleased_memcg, +}; diff --git a/tools/testing/selftests/bpf/progs/test_thp_adjust_unreleased_task.c b/tools/testing/selftests/bpf/progs/test_thp_adjust_unreleased_task.c new file mode 100644 index 000000000000..50d756810412 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_thp_adjust_unreleased_task.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include +#include + +#include "bpf_misc.h" + +char _license[] SEC("license") = "GPL"; + +SEC("struct_ops/get_suggested_order") +__failure __msg("Unreleased reference") +int BPF_PROG(thp_unreleased_task, struct mm_struct *mm, struct vm_area_struct *vma__nullable, + u64 vma_flags, u64 tva_flags, int orders) +{ + struct task_struct *p = bpf_mm_get_task(mm); + + /* The task should be released with bpf_task_release() */ + return p ? 0 : 1; +} + +SEC(".struct_ops.link") +struct bpf_thp_ops thp_task_ops = { + .get_suggested_order = (void *)thp_unreleased_task, +}; -- 2.47.3