From: Longjun Tang Add functional tests for equality, ordering, zero-size, and null-byte handling. Add negative tests for NULL, user-space, and invalid kernel pointer arguments. Signed-off-by: Longjun Tang --- .../bpf/progs/string_kfuncs_failure1.c | 9 +++++++++ .../selftests/bpf/progs/string_kfuncs_success.c | 17 +++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c index bddc4e8579d2..a85d64605d0e 100644 --- a/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_failure1.c @@ -9,6 +9,9 @@ char *user_ptr = (char *)1; char *invalid_kern_ptr = (char *)-1; +extern int bpf_memcmp(const void *ptr1__ign, const void *ptr2__ign, + size_t size) __ksym; + /* * When passing userspace pointers, the error code differs based on arch: * -ERANGE on arches with non-overlapping address spaces @@ -53,6 +56,8 @@ SEC("syscall") __retval(USER_PTR_ERR)int test_strnstr_null1(void *ctx) { return SEC("syscall") __retval(USER_PTR_ERR)int test_strnstr_null2(void *ctx) { return bpf_strnstr("hello", NULL, 1); } SEC("syscall") __retval(USER_PTR_ERR)int test_strncasestr_null1(void *ctx) { return bpf_strncasestr(NULL, "hello", 1); } SEC("syscall") __retval(USER_PTR_ERR)int test_strncasestr_null2(void *ctx) { return bpf_strncasestr("hello", NULL, 1); } +SEC("syscall") __retval(USER_PTR_ERR)int test_memcmp_null1(void *ctx) { return bpf_memcmp(NULL, "x", 1); } +SEC("syscall") __retval(USER_PTR_ERR)int test_memcmp_null2(void *ctx) { return bpf_memcmp("x", NULL, 1); } /* Passing userspace ptr to string kfuncs */ SEC("syscall") __retval(USER_PTR_ERR) int test_strcmp_user_ptr1(void *ctx) { return bpf_strcmp(user_ptr, "hello"); } @@ -79,6 +84,8 @@ SEC("syscall") __retval(USER_PTR_ERR) int test_strnstr_user_ptr1(void *ctx) { re SEC("syscall") __retval(USER_PTR_ERR) int test_strnstr_user_ptr2(void *ctx) { return bpf_strnstr("hello", user_ptr, 1); } SEC("syscall") __retval(USER_PTR_ERR) int test_strncasestr_user_ptr1(void *ctx) { return bpf_strncasestr(user_ptr, "hello", 1); } SEC("syscall") __retval(USER_PTR_ERR) int test_strncasestr_user_ptr2(void *ctx) { return bpf_strncasestr("hello", user_ptr, 1); } +SEC("syscall") __retval(USER_PTR_ERR) int test_memcmp_user_ptr1(void *ctx) { return bpf_memcmp(user_ptr, "x", 1); } +SEC("syscall") __retval(USER_PTR_ERR) int test_memcmp_user_ptr2(void *ctx) { return bpf_memcmp("x", user_ptr, 1); } #endif /* __TARGET_ARCH_s390 */ @@ -107,5 +114,7 @@ SEC("syscall") __retval(-EFAULT) int test_strnstr_pagefault1(void *ctx) { return SEC("syscall") __retval(-EFAULT) int test_strnstr_pagefault2(void *ctx) { return bpf_strnstr("hello", invalid_kern_ptr, 1); } SEC("syscall") __retval(-EFAULT) int test_strncasestr_pagefault1(void *ctx) { return bpf_strncasestr(invalid_kern_ptr, "hello", 1); } SEC("syscall") __retval(-EFAULT) int test_strncasestr_pagefault2(void *ctx) { return bpf_strncasestr("hello", invalid_kern_ptr, 1); } +SEC("syscall") __retval(-EFAULT) int test_memcmp_pagefault1(void *ctx) { return bpf_memcmp(invalid_kern_ptr, "x", 1); } +SEC("syscall") __retval(-EFAULT) int test_memcmp_pagefault2(void *ctx) { return bpf_memcmp("x", invalid_kern_ptr, 1); } char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c index f65b1226a81a..c2be9edcd282 100644 --- a/tools/testing/selftests/bpf/progs/string_kfuncs_success.c +++ b/tools/testing/selftests/bpf/progs/string_kfuncs_success.c @@ -7,6 +7,9 @@ char str[] = "hello world"; +extern int bpf_memcmp(const void *ptr1__ign, const void *ptr2__ign, + size_t size) __ksym; + #define __test(retval) SEC("syscall") __success __retval(retval) /* Functional tests */ @@ -60,4 +63,18 @@ __test(-ENOENT) int test_strncasestr_notfound2(void *ctx) { return bpf_strncases __test(-ENOENT) int test_strncasestr_notfound3(void *ctx) { return bpf_strncasestr("", "a", 0); } __test(0) int test_strncasestr_empty(void *ctx) { return bpf_strncasestr(str, "", 1); } +/* bpf_memcmp - functional tests */ +char data1[] = "hello world"; +char data2[] = "hello world"; +char data3[] = "hello worle"; +__test(0) int test_memcmp_eq(void *ctx) { return bpf_memcmp(data1, data2, sizeof(data1)); } +__test(-1) int test_memcmp_neq_less(void *ctx) { return bpf_memcmp(data1, data3, sizeof(data1)); } +__test(1) int test_memcmp_neq_greater(void *ctx) { return bpf_memcmp(data3, data1, sizeof(data1)); } +__test(0) int test_memcmp_size_zero(void *ctx) { return bpf_memcmp(data1, data3, 0); } +/* memcmp should NOT stop at null byte - compare past '\0' */ +char bin1[] = { 'a', '\0', 'c' }; +char bin2[] = { 'a', '\0', 'd' }; +__test(0) int test_memcmp_null_byte_eq(void *ctx) { return bpf_memcmp(bin1, bin1, sizeof(bin1)); } +__test(-1) int test_memcmp_null_byte_neq(void *ctx) { return bpf_memcmp(bin1, bin2, sizeof(bin1)); } + char _license[] SEC("license") = "GPL"; -- 2.25.1