Merge branch 'selftests-bpf-fixes-for-userspace-asan'

Ihor Solodrai says:

====================
selftests/bpf: Fixes for userspace ASAN

This series includes various fixes aiming to enable test_progs run
with userspace address sanitizer on BPF CI.

The first five patches add a simplified implementation of strscpy() to
selftests/bpf and then replace strcpy/strncpy usages across the tests
with it. See relevant discussions [1][2].

Patch #6 fixes the selftests/bpf/test_progs build with:

    SAN_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"

The subsequent patches fix bugs reported by the address sanitizer on
attempt to run the tests.

[1] https://lore.kernel.org/bpf/CAADnVQ+9uw2_o388j43EWiAPdMB=3FLx2jq-9zRSvqrv-wgRag@mail.gmail.com/
[2] https://lore.kernel.org/bpf/20260220182011.802116-1-ihor.solodrai@linux.dev/
---

v3->v4:
  - combine strscpy and ASAN series into one (Alexei)
  - make the count arg of strscpy() optional via macro and fixup
    relevant call sites (Alexei)
  - remove strscpy_cat() from this series (Alexei)

v3: https://lore.kernel.org/bpf/20260220222604.1155148-1-ihor.solodrai@linux.dev/

v2->v3:
  - rebase on top of "selftests/bpf: Add and use strscpy()"
    - https://lore.kernel.org/bpf/20260220182011.802116-1-ihor.solodrai@linux.dev/
  - uprobe_multi_test.c: memset static struct child at the beginning
    of a test *and* zero out child->thread in release_child (patch #9,
    Mykyta)
  - nits in test_sysctl.c (patch #11, Eduard)
  - bpftool_helpers.c: update to use strscpy (patch #14, Alexei)
  - add __asan_on_error handler to still dump test logs even with ASAN
    build (patch #15, Mykyta)

v2: https://lore.kernel.org/bpf/20260218003041.1156774-1-ihor.solodrai@linux.dev/

v1->v2:
  - rebase on bpf (v1 was targeting bpf-next)
  - add ASAN flag handling in selftests/bpf/Makefile (Eduard)
  - don't override SIGSEGV handler in test_progs with ASAN (Eduard)
  - add error messages in detect_bpftool_path (Mykyta)
  - various nits (Eduard, Jiri, Mykyta, Alexis)

v1: https://lore.kernel.org/bpf/20260212011356.3266753-1-ihor.solodrai@linux.dev/
====================

Link: https://patch.msgid.link/20260223190736.649171-1-ihor.solodrai@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Alexei Starovoitov
2026-02-23 18:40:09 -08:00
47 changed files with 290 additions and 163 deletions

View File

@@ -65,6 +65,9 @@ $(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OU
LIBELF_FLAGS := $(shell $(HOSTPKG_CONFIG) libelf --cflags 2>/dev/null)
LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf)
ZLIB_LIBS := $(shell $(HOSTPKG_CONFIG) zlib --libs 2>/dev/null || echo -lz)
ZSTD_LIBS := $(shell $(HOSTPKG_CONFIG) libzstd --libs 2>/dev/null || echo -lzstd)
HOSTCFLAGS_resolve_btfids += -g \
-I$(srctree)/tools/include \
-I$(srctree)/tools/include/uapi \
@@ -73,7 +76,7 @@ HOSTCFLAGS_resolve_btfids += -g \
$(LIBELF_FLAGS) \
-Wall -Werror
LIBS = $(LIBELF_LIBS) -lz
LIBS = $(LIBELF_LIBS) $(ZLIB_LIBS) $(ZSTD_LIBS)
export srctree OUTPUT HOSTCFLAGS_resolve_btfids Q HOSTCC HOSTLD HOSTAR
include $(srctree)/tools/build/Makefile.include
@@ -83,7 +86,7 @@ $(BINARY_IN): fixdep FORCE prepare | $(OUTPUT)
$(BINARY): $(BPFOBJ) $(SUBCMDOBJ) $(BINARY_IN)
$(call msg,LINK,$@)
$(Q)$(HOSTCC) $(BINARY_IN) $(KBUILD_HOSTLDFLAGS) -o $@ $(BPFOBJ) $(SUBCMDOBJ) $(LIBS)
$(Q)$(HOSTCC) $(BINARY_IN) $(KBUILD_HOSTLDFLAGS) $(EXTRA_LDFLAGS) -o $@ $(BPFOBJ) $(SUBCMDOBJ) $(LIBS)
clean_objects := $(wildcard $(OUTPUT)/*.o \
$(OUTPUT)/.*.o.cmd \

View File

@@ -226,7 +226,7 @@ static struct btf_id *btf_id__find(struct rb_root *root, const char *name)
}
static struct btf_id *__btf_id__add(struct rb_root *root,
char *name,
const char *name,
enum btf_id_kind kind,
bool unique)
{
@@ -250,7 +250,11 @@ static struct btf_id *__btf_id__add(struct rb_root *root,
id = zalloc(sizeof(*id));
if (id) {
pr_debug("adding symbol %s\n", name);
id->name = name;
id->name = strdup(name);
if (!id->name) {
free(id);
return NULL;
}
id->kind = kind;
rb_link_node(&id->rb_node, parent, p);
rb_insert_color(&id->rb_node, root);
@@ -258,17 +262,21 @@ static struct btf_id *__btf_id__add(struct rb_root *root,
return id;
}
static inline struct btf_id *btf_id__add(struct rb_root *root, char *name, enum btf_id_kind kind)
static inline struct btf_id *btf_id__add(struct rb_root *root,
const char *name,
enum btf_id_kind kind)
{
return __btf_id__add(root, name, kind, false);
}
static inline struct btf_id *btf_id__add_unique(struct rb_root *root, char *name, enum btf_id_kind kind)
static inline struct btf_id *btf_id__add_unique(struct rb_root *root,
const char *name,
enum btf_id_kind kind)
{
return __btf_id__add(root, name, kind, true);
}
static char *get_id(const char *prefix_end)
static int get_id(const char *prefix_end, char *buf, size_t buf_sz)
{
/*
* __BTF_ID__func__vfs_truncate__0
@@ -277,28 +285,28 @@ static char *get_id(const char *prefix_end)
*/
int len = strlen(prefix_end);
int pos = sizeof("__") - 1;
char *p, *id;
char *p;
if (pos >= len)
return NULL;
return -1;
id = strdup(prefix_end + pos);
if (id) {
/*
* __BTF_ID__func__vfs_truncate__0
* id = ^
*
* cut the unique id part
*/
p = strrchr(id, '_');
p--;
if (*p != '_') {
free(id);
return NULL;
}
*p = '\0';
}
return id;
if (len - pos >= buf_sz)
return -1;
strcpy(buf, prefix_end + pos);
/*
* __BTF_ID__func__vfs_truncate__0
* buf = ^
*
* cut the unique id part
*/
p = strrchr(buf, '_');
p--;
if (*p != '_')
return -1;
*p = '\0';
return 0;
}
static struct btf_id *add_set(struct object *obj, char *name, enum btf_id_kind kind)
@@ -335,10 +343,9 @@ static struct btf_id *add_set(struct object *obj, char *name, enum btf_id_kind k
static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size)
{
char *id;
char id[KSYM_NAME_LEN];
id = get_id(name + size);
if (!id) {
if (get_id(name + size, id, sizeof(id))) {
pr_err("FAILED to parse symbol name: %s\n", name);
return NULL;
}
@@ -346,6 +353,21 @@ static struct btf_id *add_symbol(struct rb_root *root, char *name, size_t size)
return btf_id__add(root, id, BTF_ID_KIND_SYM);
}
static void btf_id__free_all(struct rb_root *root)
{
struct rb_node *next;
struct btf_id *id;
next = rb_first(root);
while (next) {
id = rb_entry(next, struct btf_id, rb_node);
next = rb_next(&id->rb_node);
rb_erase(&id->rb_node, root);
free(id->name);
free(id);
}
}
static void bswap_32_data(void *data, u32 nr_bytes)
{
u32 cnt, i;
@@ -1547,6 +1569,11 @@ dump_btf:
out:
btf__free(obj.base_btf);
btf__free(obj.btf);
btf_id__free_all(&obj.structs);
btf_id__free_all(&obj.unions);
btf_id__free_all(&obj.typedefs);
btf_id__free_all(&obj.funcs);
btf_id__free_all(&obj.sets);
if (obj.efile.elf) {
elf_end(obj.efile.elf);
close(obj.efile.fd);

View File

@@ -22,7 +22,11 @@
#define COUNT_ARGS(X...) __COUNT_ARGS(, ##X, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
/* Concatenate two parameters, but allow them to be expanded beforehand. */
#ifndef __CONCAT
#define __CONCAT(a, b) a ## b
#endif
#ifndef CONCATENATE
#define CONCATENATE(a, b) __CONCAT(a, b)
#endif
#endif /* _LINUX_ARGS_H */

View File

@@ -0,0 +1,3 @@
*arena*
task_local_data
uprobe_multi_test

View File

@@ -27,7 +27,11 @@ ifneq ($(wildcard $(GENHDR)),)
endif
BPF_GCC ?= $(shell command -v bpf-gcc;)
ifdef ASAN
SAN_CFLAGS ?= -fsanitize=address -fno-omit-frame-pointer
else
SAN_CFLAGS ?=
endif
SAN_LDFLAGS ?= $(SAN_CFLAGS)
RELEASE ?=
OPT_FLAGS ?= $(if $(RELEASE),-O2,-O0)
@@ -326,8 +330,8 @@ $(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
$(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/bpftool
$(Q)$(MAKE) $(submake_extras) -C $(BPFTOOLDIR) \
ARCH= CROSS_COMPILE= CC="$(HOSTCC)" LD="$(HOSTLD)" \
EXTRA_CFLAGS='-g $(OPT_FLAGS) $(EXTRA_CFLAGS)' \
EXTRA_LDFLAGS='$(EXTRA_LDFLAGS)' \
EXTRA_CFLAGS='-g $(OPT_FLAGS) $(SAN_CFLAGS) $(EXTRA_CFLAGS)' \
EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \
OUTPUT=$(HOST_BUILD_DIR)/bpftool/ \
LIBBPF_OUTPUT=$(HOST_BUILD_DIR)/libbpf/ \
LIBBPF_DESTDIR=$(HOST_SCRATCH_DIR)/ \
@@ -338,8 +342,8 @@ $(CROSS_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \
$(BPFOBJ) | $(BUILD_DIR)/bpftool
$(Q)$(MAKE) $(submake_extras) -C $(BPFTOOLDIR) \
ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) \
EXTRA_CFLAGS='-g $(OPT_FLAGS) $(EXTRA_CFLAGS)' \
EXTRA_LDFLAGS='$(EXTRA_LDFLAGS)' \
EXTRA_CFLAGS='-g $(OPT_FLAGS) $(SAN_CFLAGS) $(EXTRA_CFLAGS)' \
EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \
OUTPUT=$(BUILD_DIR)/bpftool/ \
LIBBPF_OUTPUT=$(BUILD_DIR)/libbpf/ \
LIBBPF_DESTDIR=$(SCRATCH_DIR)/ \
@@ -404,6 +408,7 @@ $(RESOLVE_BTFIDS): $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/resolve_btfids \
$(Q)$(MAKE) $(submake_extras) -C $(TOOLSDIR)/bpf/resolve_btfids \
CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" \
LIBBPF_INCLUDE=$(HOST_INCLUDE_DIR) \
EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \
OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/ BPFOBJ=$(HOST_BPFOBJ)
# Get Clang's default includes on this system, as opposed to those seen by

View File

@@ -230,8 +230,8 @@ static void trigger_fentry_setup(void)
static void attach_ksyms_all(struct bpf_program *empty, bool kretprobe)
{
LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
char **syms = NULL;
size_t cnt = 0;
struct bpf_link *link = NULL;
struct ksyms *ksyms = NULL;
/* Some recursive functions will be skipped in
* bpf_get_ksyms -> skip_entry, as they can introduce sufficient
@@ -241,16 +241,18 @@ static void attach_ksyms_all(struct bpf_program *empty, bool kretprobe)
* So, don't run the kprobe-multi-all and kretprobe-multi-all on
* a debug kernel.
*/
if (bpf_get_ksyms(&syms, &cnt, true)) {
if (bpf_get_ksyms(&ksyms, true)) {
fprintf(stderr, "failed to get ksyms\n");
exit(1);
}
opts.syms = (const char **) syms;
opts.cnt = cnt;
opts.syms = (const char **)ksyms->filtered_syms;
opts.cnt = ksyms->filtered_cnt;
opts.retprobe = kretprobe;
/* attach empty to all the kernel functions except bpf_get_numa_node_id. */
if (!bpf_program__attach_kprobe_multi_opts(empty, NULL, &opts)) {
link = bpf_program__attach_kprobe_multi_opts(empty, NULL, &opts);
free_kallsyms_local(ksyms);
if (!link) {
fprintf(stderr, "failed to attach bpf_program__attach_kprobe_multi_opts to all\n");
exit(1);
}

View File

@@ -8,6 +8,7 @@
#include <errno.h>
#include <syscall.h>
#include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
#include <linux/args.h>
static inline unsigned int bpf_num_possible_cpus(void)
{
@@ -21,25 +22,43 @@ static inline unsigned int bpf_num_possible_cpus(void)
return possible_cpus;
}
/* Copy up to sz - 1 bytes from zero-terminated src string and ensure that dst
* is zero-terminated string no matter what (unless sz == 0, in which case
* it's a no-op). It's conceptually close to FreeBSD's strlcpy(), but differs
* in what is returned. Given this is internal helper, it's trivial to extend
* this, when necessary. Use this instead of strncpy inside libbpf source code.
/*
* Simplified strscpy() implementation. The kernel one is in lib/string.c
*/
static inline void bpf_strlcpy(char *dst, const char *src, size_t sz)
static inline ssize_t sized_strscpy(char *dest, const char *src, size_t count)
{
size_t i;
long res = 0;
if (sz == 0)
return;
if (count == 0)
return -E2BIG;
sz--;
for (i = 0; i < sz && src[i]; i++)
dst[i] = src[i];
dst[i] = '\0';
while (count > 1) {
char c;
c = src[res];
dest[res] = c;
if (!c)
return res;
res++;
count--;
}
/* Force NUL-termination. */
dest[res] = '\0';
/* Return E2BIG if the source didn't stop */
return src[res] ? -E2BIG : res;
}
#define __strscpy0(dst, src, ...) \
sized_strscpy(dst, src, sizeof(dst))
#define __strscpy1(dst, src, size) \
sized_strscpy(dst, src, size)
#undef strscpy /* Redefine the placeholder from tools/include/linux/string.h */
#define strscpy(dst, src, ...) \
CONCATENATE(__strscpy, COUNT_ARGS(__VA_ARGS__))(dst, src, __VA_ARGS__)
#define __bpf_percpu_val_align __attribute__((__aligned__(8)))
#define BPF_DECLARE_PERCPU(type, name) \

View File

@@ -1,24 +1,37 @@
// SPDX-License-Identifier: GPL-2.0-only
#include "bpftool_helpers.h"
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include "bpf_util.h"
#include "bpftool_helpers.h"
#define BPFTOOL_PATH_MAX_LEN 64
#define BPFTOOL_FULL_CMD_MAX_LEN 512
#define BPFTOOL_DEFAULT_PATH "tools/sbin/bpftool"
static int detect_bpftool_path(char *buffer)
static int detect_bpftool_path(char *buffer, size_t size)
{
char tmp[BPFTOOL_PATH_MAX_LEN];
const char *env_path;
/* First, check if BPFTOOL environment variable is set */
env_path = getenv("BPFTOOL");
if (env_path && access(env_path, X_OK) == 0) {
strscpy(buffer, env_path, size);
return 0;
} else if (env_path) {
fprintf(stderr, "bpftool '%s' doesn't exist or is not executable\n", env_path);
return 1;
}
/* Check default bpftool location (will work if we are running the
* default flavor of test_progs)
*/
snprintf(tmp, BPFTOOL_PATH_MAX_LEN, "./%s", BPFTOOL_DEFAULT_PATH);
if (access(tmp, X_OK) == 0) {
strncpy(buffer, tmp, BPFTOOL_PATH_MAX_LEN);
strscpy(buffer, tmp, size);
return 0;
}
@@ -27,11 +40,11 @@ static int detect_bpftool_path(char *buffer)
*/
snprintf(tmp, BPFTOOL_PATH_MAX_LEN, "../%s", BPFTOOL_DEFAULT_PATH);
if (access(tmp, X_OK) == 0) {
strncpy(buffer, tmp, BPFTOOL_PATH_MAX_LEN);
strscpy(buffer, tmp, size);
return 0;
}
/* Failed to find bpftool binary */
fprintf(stderr, "Failed to detect bpftool path, use BPFTOOL env var to override\n");
return 1;
}
@@ -44,7 +57,7 @@ static int run_command(char *args, char *output_buf, size_t output_max_len)
int ret;
/* Detect and cache bpftool binary location */
if (bpftool_path[0] == 0 && detect_bpftool_path(bpftool_path))
if (bpftool_path[0] == 0 && detect_bpftool_path(bpftool_path, sizeof(bpftool_path)))
return 1;
ret = snprintf(command, BPFTOOL_FULL_CMD_MAX_LEN, "%s %s%s",

View File

@@ -86,7 +86,7 @@ static int __enable_controllers(const char *cgroup_path, const char *controllers
enable[len] = 0;
close(fd);
} else {
bpf_strlcpy(enable, controllers, sizeof(enable));
strscpy(enable, controllers);
}
snprintf(path, sizeof(path), "%s/cgroup.subtree_control", cgroup_path);

View File

@@ -122,15 +122,15 @@ static int disasm_one_func(FILE *text_out, uint8_t *image, __u32 len)
pc += cnt;
}
qsort(labels.pcs, labels.cnt, sizeof(*labels.pcs), cmp_u32);
for (i = 0; i < labels.cnt; ++i)
/* gcc is unable to infer upper bound for labels.cnt and assumes
* it to be U32_MAX. U32_MAX takes 10 decimal digits.
* snprintf below prints into labels.names[*],
* which has space only for two digits and a letter.
* To avoid truncation warning use (i % MAX_LOCAL_LABELS),
* which informs gcc about printed value upper bound.
*/
snprintf(labels.names[i], sizeof(labels.names[i]), "L%d", i % MAX_LOCAL_LABELS);
/* gcc is unable to infer upper bound for labels.cnt and
* assumes it to be U32_MAX. U32_MAX takes 10 decimal digits.
* snprintf below prints into labels.names[*], which has space
* only for two digits and a letter. To avoid truncation
* warning use (i < MAX_LOCAL_LABELS), which informs gcc about
* printed value upper bound.
*/
for (i = 0; i < labels.cnt && i < MAX_LOCAL_LABELS; ++i)
snprintf(labels.names[i], sizeof(labels.names[i]), "L%d", i);
/* now print with labels */
labels.print_phase = true;

View File

@@ -432,7 +432,7 @@ int make_sockaddr(int family, const char *addr_str, __u16 port,
memset(addr, 0, sizeof(*sun));
sun->sun_family = family;
sun->sun_path[0] = 0;
strcpy(sun->sun_path + 1, addr_str);
strscpy(sun->sun_path + 1, addr_str, sizeof(sun->sun_path) - 1);
if (len)
*len = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(addr_str);
return 0;
@@ -581,8 +581,7 @@ int open_tuntap(const char *dev_name, bool need_mac)
return -1;
ifr.ifr_flags = IFF_NO_PI | (need_mac ? IFF_TAP : IFF_TUN);
strncpy(ifr.ifr_name, dev_name, IFNAMSIZ - 1);
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
strscpy(ifr.ifr_name, dev_name);
err = ioctl(fd, TUNSETIFF, &ifr);
if (!ASSERT_OK(err, "ioctl(TUNSETIFF)")) {

View File

@@ -346,8 +346,7 @@ static void test_task_sleepable(void)
close(finish_pipe[1]);
test_data = malloc(sizeof(char) * 10);
strncpy(test_data, "test_data", 10);
test_data[9] = '\0';
strscpy(test_data, "test_data", 10);
test_data_long = malloc(sizeof(char) * 5000);
for (int i = 0; i < 5000; ++i) {

View File

@@ -281,7 +281,7 @@ static void test_dctcp_fallback(void)
dctcp_skel = bpf_dctcp__open();
if (!ASSERT_OK_PTR(dctcp_skel, "dctcp_skel"))
return;
strcpy(dctcp_skel->rodata->fallback_cc, "cubic");
strscpy(dctcp_skel->rodata->fallback_cc, "cubic");
if (!ASSERT_OK(bpf_dctcp__load(dctcp_skel), "bpf_dctcp__load"))
goto done;

View File

@@ -202,7 +202,7 @@ static void test_cgroup_iter_sleepable(int cgroup_fd, __u64 cgroup_id)
iter_fd = bpf_iter_create(bpf_link__fd(link));
if (!ASSERT_GE(iter_fd, 0, "iter_create"))
goto out;
goto out_link;
/* trigger the program run */
(void)read(iter_fd, buf, sizeof(buf));
@@ -210,6 +210,8 @@ static void test_cgroup_iter_sleepable(int cgroup_fd, __u64 cgroup_id)
ASSERT_EQ(skel->bss->cgroup_id, cgroup_id, "cgroup_id");
close(iter_fd);
out_link:
bpf_link__destroy(link);
out:
cgrp_ls_sleepable__destroy(skel);
}

View File

@@ -308,8 +308,10 @@ static int find_field_offset(struct btf *btf, char *pattern, regmatch_t *matches
return -1;
}
strncpy(type_str, type, type_sz);
strncpy(field_str, field, field_sz);
memcpy(type_str, type, type_sz);
type_str[type_sz] = '\0';
memcpy(field_str, field, field_sz);
field_str[field_sz] = '\0';
btf_id = btf__find_by_name(btf, type_str);
if (btf_id < 0) {
PRINT_FAIL("No BTF info for type %s\n", type_str);

View File

@@ -137,11 +137,14 @@ static void verify_success(const char *prog_name, enum test_setup_type setup_typ
);
link = bpf_program__attach(prog);
if (!ASSERT_OK_PTR(link, "bpf_program__attach"))
if (!ASSERT_OK_PTR(link, "bpf_program__attach")) {
bpf_object__close(obj);
goto cleanup;
}
err = bpf_prog_test_run_opts(aux_prog_fd, &topts);
bpf_link__destroy(link);
bpf_object__close(obj);
if (!ASSERT_OK(err, "test_run"))
goto cleanup;

View File

@@ -412,8 +412,8 @@ static void check_fd_array_cnt__fd_array_too_big(void)
ASSERT_EQ(prog_fd, -E2BIG, "prog should have been rejected with -E2BIG");
cleanup_fds:
while (i > 0)
Close(extra_fds[--i]);
while (i-- > 0)
Close(extra_fds[i]);
}
void test_fd_array_cnt(void)

View File

@@ -570,7 +570,7 @@ static int create_tap(const char *ifname)
};
int fd, ret;
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
strscpy(ifr.ifr_name, ifname);
fd = open("/dev/net/tun", O_RDWR);
if (fd < 0)
@@ -599,7 +599,7 @@ static int ifup(const char *ifname)
struct ifreq ifr = {};
int sk, ret;
strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
strscpy(ifr.ifr_name, ifname);
sk = socket(PF_INET, SOCK_DGRAM, 0);
if (sk < 0)

View File

@@ -61,6 +61,7 @@ static void test_reenter_update(void)
ASSERT_EQ(skel->bss->update_err, -EDEADLK, "no reentrancy");
out:
free(value);
htab_update__destroy(skel);
}

View File

@@ -104,11 +104,8 @@ void test_kmem_cache_iter(void)
if (!ASSERT_GE(iter_fd, 0, "iter_create"))
goto destroy;
memset(buf, 0, sizeof(buf));
while (read(iter_fd, buf, sizeof(buf)) > 0) {
/* Read out all contents */
printf("%s", buf);
}
while (read(iter_fd, buf, sizeof(buf)) > 0)
; /* Read out all contents */
/* Next reads should return 0 */
ASSERT_EQ(read(iter_fd, buf, sizeof(buf)), 0, "read");

View File

@@ -456,25 +456,23 @@ static void test_kprobe_multi_bench_attach(bool kernel)
{
LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
struct kprobe_multi_empty *skel = NULL;
char **syms = NULL;
size_t cnt = 0;
struct ksyms *ksyms = NULL;
if (!ASSERT_OK(bpf_get_ksyms(&syms, &cnt, kernel), "bpf_get_ksyms"))
if (!ASSERT_OK(bpf_get_ksyms(&ksyms, kernel), "bpf_get_ksyms"))
return;
skel = kprobe_multi_empty__open_and_load();
if (!ASSERT_OK_PTR(skel, "kprobe_multi_empty__open_and_load"))
goto cleanup;
opts.syms = (const char **) syms;
opts.cnt = cnt;
opts.syms = (const char **)ksyms->filtered_syms;
opts.cnt = ksyms->filtered_cnt;
do_bench_test(skel, &opts);
cleanup:
kprobe_multi_empty__destroy(skel);
if (syms)
free(syms);
free_kallsyms_local(ksyms);
}
static void test_kprobe_multi_bench_attach_addr(bool kernel)

View File

@@ -117,7 +117,7 @@ void test_lwt_seg6local(void)
const char *ns1 = NETNS_BASE "1";
const char *ns6 = NETNS_BASE "6";
struct nstoken *nstoken = NULL;
const char *foobar = "foobar";
const char foobar[] = "foobar";
ssize_t bytes;
int sfd, cfd;
char buf[7];

View File

@@ -28,9 +28,9 @@ static void test_queue_stack_map_by_type(int type)
vals[i] = rand();
if (type == QUEUE)
strncpy(file, "./test_queue_map.bpf.o", sizeof(file));
strscpy(file, "./test_queue_map.bpf.o");
else if (type == STACK)
strncpy(file, "./test_stack_map.bpf.o", sizeof(file));
strscpy(file, "./test_stack_map.bpf.o");
else
return;

View File

@@ -212,7 +212,7 @@ void test_setget_sockopt(void)
if (!ASSERT_OK_PTR(skel, "open skel"))
goto done;
strcpy(skel->rodata->veth, "binddevtest1");
strscpy(skel->rodata->veth, "binddevtest1");
skel->rodata->veth_ifindex = if_nametoindex("binddevtest1");
if (!ASSERT_GT(skel->rodata->veth_ifindex, 0, "if_nametoindex"))
goto done;

View File

@@ -34,7 +34,7 @@ void test_skc_to_unix_sock(void)
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sun_family = AF_UNIX;
strncpy(sockaddr.sun_path, sock_path, strlen(sock_path));
strscpy(sockaddr.sun_path, sock_path);
sockaddr.sun_path[0] = '\0';
err = bind(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));

View File

@@ -204,7 +204,7 @@ static void test_skmsg_helpers_with_link(enum bpf_map_type map_type)
/* Fail since bpf_link for the same prog type has been created. */
link2 = bpf_program__attach_sockmap(prog_clone, map);
if (!ASSERT_ERR_PTR(link2, "bpf_program__attach_sockmap")) {
bpf_link__detach(link2);
bpf_link__destroy(link2);
goto out;
}
@@ -230,7 +230,7 @@ static void test_skmsg_helpers_with_link(enum bpf_map_type map_type)
if (!ASSERT_OK(err, "bpf_link_update"))
goto out;
out:
bpf_link__detach(link);
bpf_link__destroy(link);
test_skmsg_load_helpers__destroy(skel);
}
@@ -417,7 +417,7 @@ static void test_sockmap_skb_verdict_attach_with_link(void)
if (!ASSERT_OK_PTR(link, "bpf_program__attach_sockmap"))
goto out;
bpf_link__detach(link);
bpf_link__destroy(link);
err = bpf_prog_attach(bpf_program__fd(prog), map, BPF_SK_SKB_STREAM_VERDICT, 0);
if (!ASSERT_OK(err, "bpf_prog_attach"))
@@ -426,7 +426,7 @@ static void test_sockmap_skb_verdict_attach_with_link(void)
/* Fail since attaching with the same prog/map has been done. */
link = bpf_program__attach_sockmap(prog, map);
if (!ASSERT_ERR_PTR(link, "bpf_program__attach_sockmap"))
bpf_link__detach(link);
bpf_link__destroy(link);
err = bpf_prog_detach2(bpf_program__fd(prog), map, BPF_SK_SKB_STREAM_VERDICT);
if (!ASSERT_OK(err, "bpf_prog_detach2"))
@@ -747,13 +747,13 @@ static void test_sockmap_skb_verdict_peek_with_link(void)
test_sockmap_skb_verdict_peek_helper(map);
ASSERT_EQ(pass->bss->clone_called, 1, "clone_called");
out:
bpf_link__detach(link);
bpf_link__destroy(link);
test_sockmap_pass_prog__destroy(pass);
}
static void test_sockmap_unconnected_unix(void)
{
int err, map, stream = 0, dgram = 0, zero = 0;
int err, map, stream = -1, dgram = -1, zero = 0;
struct test_sockmap_pass_prog *skel;
skel = test_sockmap_pass_prog__open_and_load();
@@ -764,22 +764,22 @@ static void test_sockmap_unconnected_unix(void)
stream = xsocket(AF_UNIX, SOCK_STREAM, 0);
if (stream < 0)
return;
goto out;
dgram = xsocket(AF_UNIX, SOCK_DGRAM, 0);
if (dgram < 0) {
close(stream);
return;
}
if (dgram < 0)
goto out;
err = bpf_map_update_elem(map, &zero, &stream, BPF_ANY);
ASSERT_ERR(err, "bpf_map_update_elem(stream)");
if (!ASSERT_ERR(err, "bpf_map_update_elem(stream)"))
goto out;
err = bpf_map_update_elem(map, &zero, &dgram, BPF_ANY);
ASSERT_OK(err, "bpf_map_update_elem(dgram)");
out:
close(stream);
close(dgram);
test_sockmap_pass_prog__destroy(skel);
}
static void test_sockmap_many_socket(void)
@@ -1027,7 +1027,7 @@ static void test_sockmap_skb_verdict_vsock_poll(void)
if (xrecv_nonblock(conn, &buf, 1, 0) != 1)
FAIL("xrecv_nonblock");
detach:
bpf_link__detach(link);
bpf_link__destroy(link);
close:
xclose(conn);
xclose(peer);

View File

@@ -899,7 +899,7 @@ static void test_msg_redir_to_listening_with_link(struct test_sockmap_listen *sk
redir_to_listening(family, sotype, sock_map, verdict_map, REDIR_EGRESS);
bpf_link__detach(link);
bpf_link__destroy(link);
}
static void redir_partial(int family, int sotype, int sock_map, int parser_map)

View File

@@ -142,7 +142,7 @@ static int getsetsockopt(void)
/* TCP_CONGESTION can extend the string */
strcpy(buf.cc, "nv");
strscpy(buf.cc, "nv");
err = setsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, strlen("nv"));
if (err) {
log_err("Failed to call setsockopt(TCP_CONGESTION)");

View File

@@ -54,9 +54,7 @@ static void test_private_stack_fail(void)
}
err = struct_ops_private_stack_fail__load(skel);
if (!ASSERT_ERR(err, "struct_ops_private_stack_fail__load"))
goto cleanup;
return;
ASSERT_ERR(err, "struct_ops_private_stack_fail__load");
cleanup:
struct_ops_private_stack_fail__destroy(skel);

View File

@@ -262,7 +262,7 @@ retry:
if (!atomic_compare_exchange_strong(&tld_meta_p->cnt, &cnt, cnt + 1))
goto retry;
strncpy(tld_meta_p->metadata[i].name, name, TLD_NAME_LEN);
strscpy(tld_meta_p->metadata[i].name, name);
atomic_store(&tld_meta_p->metadata[i].size, size);
return (tld_key_t){(__s16)off};
}

View File

@@ -1360,10 +1360,8 @@ static void test_tc_opts_dev_cleanup_target(int target)
assert_mprog_count_ifindex(ifindex, target, 4);
ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
return;
goto cleanup;
cleanup3:
err = bpf_prog_detach_opts(fd3, loopback, target, &optd);
ASSERT_OK(err, "prog_detach");

View File

@@ -1095,7 +1095,7 @@ static int tun_open(char *name)
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
if (*name)
strncpy(ifr.ifr_name, name, IFNAMSIZ);
strscpy(ifr.ifr_name, name);
err = ioctl(fd, TUNSETIFF, &ifr);
if (!ASSERT_OK(err, "ioctl TUNSETIFF"))

View File

@@ -27,6 +27,7 @@ struct sysctl_test {
OP_EPERM,
SUCCESS,
} result;
struct bpf_object *obj;
};
static struct sysctl_test tests[] = {
@@ -1471,6 +1472,7 @@ static int load_sysctl_prog_file(struct sysctl_test *test)
return -1;
}
test->obj = obj;
return prog_fd;
}
@@ -1573,6 +1575,7 @@ out:
/* Detaching w/o checking return code: best effort attempt. */
if (progfd != -1)
bpf_prog_detach(cgfd, atype);
bpf_object__close(test->obj);
close(progfd);
printf("[%s]\n", err ? "FAIL" : "PASS");
return err;

View File

@@ -699,7 +699,7 @@ void test_tc_tunnel(void)
return;
if (!ASSERT_OK(setup(), "global setup"))
return;
goto out;
for (i = 0; i < ARRAY_SIZE(subtests_cfg); i++) {
cfg = &subtests_cfg[i];
@@ -711,4 +711,7 @@ void test_tc_tunnel(void)
subtest_cleanup(cfg);
}
cleanup();
out:
test_tc_tunnel__destroy(skel);
}

View File

@@ -24,9 +24,9 @@ static struct fixture *init_fixture(void)
/* for no_alu32 and cpuv4 veristat is in parent folder */
if (access("./veristat", F_OK) == 0)
strcpy(fix->veristat, "./veristat");
strscpy(fix->veristat, "./veristat");
else if (access("../veristat", F_OK) == 0)
strcpy(fix->veristat, "../veristat");
strscpy(fix->veristat, "../veristat");
else
PRINT_FAIL("Can't find veristat binary");

View File

@@ -2003,9 +2003,17 @@ int testapp_stats_tx_invalid_descs(struct test_spec *test)
int testapp_stats_rx_full(struct test_spec *test)
{
if (pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE))
struct pkt_stream *tmp;
tmp = pkt_stream_generate(DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE);
if (!tmp)
return TEST_FAILURE;
test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE);
test->ifobj_tx->xsk->pkt_stream = tmp;
tmp = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE);
if (!tmp)
return TEST_FAILURE;
test->ifobj_rx->xsk->pkt_stream = tmp;
test->ifobj_rx->xsk->rxqsize = DEFAULT_UMEM_BUFFERS;
test->ifobj_rx->release_rx = false;
@@ -2015,9 +2023,17 @@ int testapp_stats_rx_full(struct test_spec *test)
int testapp_stats_fill_empty(struct test_spec *test)
{
if (pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE))
struct pkt_stream *tmp;
tmp = pkt_stream_generate(DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE);
if (!tmp)
return TEST_FAILURE;
test->ifobj_rx->xsk->pkt_stream = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE);
test->ifobj_tx->xsk->pkt_stream = tmp;
tmp = pkt_stream_generate(DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE);
if (!tmp)
return TEST_FAILURE;
test->ifobj_rx->xsk->pkt_stream = tmp;
test->ifobj_rx->use_fill_ring = false;
test->ifobj_rx->validation_func = validate_fill_empty;

View File

@@ -62,8 +62,10 @@ static void release_child(struct child *child)
return;
close(child->go[1]);
close(child->go[0]);
if (child->thread)
if (child->thread) {
pthread_join(child->thread, NULL);
child->thread = 0;
}
close(child->c2p[0]);
close(child->c2p[1]);
if (child->pid > 0)
@@ -331,6 +333,8 @@ test_attach_api(const char *binary, const char *pattern, struct bpf_uprobe_multi
{
static struct child child;
memset(&child, 0, sizeof(child));
/* no pid filter */
__test_attach_api(binary, pattern, opts, NULL);

View File

@@ -47,7 +47,7 @@ static int load_prog(struct bpf_prog_load_opts *opts, bool expect_load_error)
static void verif_log_subtest(const char *name, bool expect_load_error, int log_level)
{
LIBBPF_OPTS(bpf_prog_load_opts, opts);
char *exp_log, prog_name[16], op_name[32];
char *exp_log, prog_name[24], op_name[32];
struct test_log_buf *skel;
struct bpf_program *prog;
size_t fixed_log_sz;

View File

@@ -126,10 +126,10 @@ static int open_xsk(int ifindex, struct xsk *xsk)
static void close_xsk(struct xsk *xsk)
{
if (xsk->umem)
xsk_umem__delete(xsk->umem);
if (xsk->socket)
xsk_socket__delete(xsk->socket);
if (xsk->umem)
xsk_umem__delete(xsk->umem);
munmap(xsk->umem_area, UMEM_SIZE);
}

View File

@@ -1261,14 +1261,8 @@ int get_bpf_max_tramp_links(void)
return ret;
}
#define MAX_BACKTRACE_SZ 128
void crash_handler(int signum)
static void dump_crash_log(void)
{
void *bt[MAX_BACKTRACE_SZ];
size_t sz;
sz = backtrace(bt, ARRAY_SIZE(bt));
fflush(stdout);
stdout = env.stdout_saved;
stderr = env.stderr_saved;
@@ -1277,12 +1271,32 @@ void crash_handler(int signum)
env.test_state->error_cnt++;
dump_test_log(env.test, env.test_state, true, false, NULL);
}
}
#define MAX_BACKTRACE_SZ 128
void crash_handler(int signum)
{
void *bt[MAX_BACKTRACE_SZ];
size_t sz;
sz = backtrace(bt, ARRAY_SIZE(bt));
dump_crash_log();
if (env.worker_id != -1)
fprintf(stderr, "[%d]: ", env.worker_id);
fprintf(stderr, "Caught signal #%d!\nStack trace:\n", signum);
backtrace_symbols_fd(bt, sz, STDERR_FILENO);
}
#ifdef __SANITIZE_ADDRESS__
void __asan_on_error(void)
{
dump_crash_log();
}
#endif
void hexdump(const char *prefix, const void *buf, size_t len)
{
for (int i = 0; i < len; i++) {
@@ -1799,7 +1813,7 @@ static int worker_main_send_subtests(int sock, struct test_state *state)
msg.subtest_done.num = i;
strncpy(msg.subtest_done.name, subtest_state->name, MAX_SUBTEST_NAME);
strscpy(msg.subtest_done.name, subtest_state->name, MAX_SUBTEST_NAME);
msg.subtest_done.error_cnt = subtest_state->error_cnt;
msg.subtest_done.skipped = subtest_state->skipped;
@@ -1944,13 +1958,15 @@ int main(int argc, char **argv)
.parser = parse_arg,
.doc = argp_program_doc,
};
int err, i;
#ifndef __SANITIZE_ADDRESS__
struct sigaction sigact = {
.sa_handler = crash_handler,
.sa_flags = SA_RESETHAND,
};
int err, i;
};
sigaction(SIGSEGV, &sigact, NULL);
#endif
env.stdout_saved = stdout;
env.stderr_saved = stderr;

View File

@@ -1320,7 +1320,7 @@ static bool cmp_str_seq(const char *log, const char *exp)
printf("FAIL\nTestcase bug\n");
return false;
}
strncpy(needle, exp, len);
memcpy(needle, exp, len);
needle[len] = 0;
q = strstr(log, needle);
if (!q) {

View File

@@ -212,6 +212,7 @@ int parse_test_list_file(const char *path,
break;
}
free(buf);
fclose(f);
return err;
}

View File

@@ -24,12 +24,6 @@
#define TRACEFS_PIPE "/sys/kernel/tracing/trace_pipe"
#define DEBUGFS_PIPE "/sys/kernel/debug/tracing/trace_pipe"
struct ksyms {
struct ksym *syms;
size_t sym_cap;
size_t sym_cnt;
};
static struct ksyms *ksyms;
static pthread_mutex_t ksyms_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -54,6 +48,8 @@ void free_kallsyms_local(struct ksyms *ksyms)
if (!ksyms)
return;
free(ksyms->filtered_syms);
if (!ksyms->syms) {
free(ksyms);
return;
@@ -610,7 +606,7 @@ static int search_kallsyms_compare(const void *p1, const struct ksym *p2)
return compare_name(p1, p2->name);
}
int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel)
int bpf_get_ksyms(struct ksyms **ksymsp, bool kernel)
{
size_t cap = 0, cnt = 0;
char *name = NULL, *ksym_name, **syms = NULL;
@@ -637,8 +633,10 @@ int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel)
else
f = fopen("/sys/kernel/debug/tracing/available_filter_functions", "r");
if (!f)
if (!f) {
free_kallsyms_local(ksyms);
return -EINVAL;
}
map = hashmap__new(symbol_hash, symbol_equal, NULL);
if (IS_ERR(map)) {
@@ -679,15 +677,18 @@ int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel)
syms[cnt++] = ksym_name;
}
*symsp = syms;
*cntp = cnt;
ksyms->filtered_syms = syms;
ksyms->filtered_cnt = cnt;
*ksymsp = ksyms;
error:
free(name);
fclose(f);
hashmap__free(map);
if (err)
if (err) {
free(syms);
free_kallsyms_local(ksyms);
}
return err;
}

View File

@@ -23,7 +23,14 @@ struct ksym {
long addr;
char *name;
};
struct ksyms;
struct ksyms {
struct ksym *syms;
size_t sym_cap;
size_t sym_cnt;
char **filtered_syms;
size_t filtered_cnt;
};
typedef int (*ksym_cmp_t)(const void *p1, const void *p2);
typedef int (*ksym_search_cmp_t)(const void *p1, const struct ksym *p2);
@@ -53,7 +60,7 @@ ssize_t get_rel_offset(uintptr_t addr);
int read_build_id(const char *path, char *build_id, size_t size);
int bpf_get_ksyms(char ***symsp, size_t *cntp, bool kernel);
int bpf_get_ksyms(struct ksyms **ksymsp, bool kernel);
int bpf_get_addrs(unsigned long **addrsp, size_t *cntp, bool kernel);
#endif

View File

@@ -3378,6 +3378,8 @@ int main(int argc, char **argv)
}
}
free(env.presets[i].atoms);
if (env.presets[i].value.type == ENUMERATOR)
free(env.presets[i].value.svalue);
}
free(env.presets);
return -err;

View File

@@ -16,6 +16,7 @@
#include <network_helpers.h>
#include "bpf_util.h"
#include "xdp_features.skel.h"
#include "xdp_features.h"
@@ -212,7 +213,7 @@ static void set_env_default(void)
env.feature.drv_feature = NETDEV_XDP_ACT_NDO_XMIT;
env.feature.action = -EINVAL;
env.ifindex = -ENODEV;
strcpy(env.ifname, "unknown");
strscpy(env.ifname, "unknown");
make_sockaddr(AF_INET6, "::ffff:127.0.0.1", DUT_CTRL_PORT,
&env.dut_ctrl_addr, NULL);
make_sockaddr(AF_INET6, "::ffff:127.0.0.1", DUT_ECHO_PORT,

View File

@@ -550,7 +550,7 @@ static int rxq_num(const char *ifname)
struct ifreq ifr = {
.ifr_data = (void *)&ch,
};
strncpy(ifr.ifr_name, ifname, IF_NAMESIZE - 1);
strscpy(ifr.ifr_name, ifname);
int fd, ret;
fd = socket(AF_UNIX, SOCK_DGRAM, 0);
@@ -571,7 +571,7 @@ static void hwtstamp_ioctl(int op, const char *ifname, struct hwtstamp_config *c
struct ifreq ifr = {
.ifr_data = (void *)cfg,
};
strncpy(ifr.ifr_name, ifname, IF_NAMESIZE - 1);
strscpy(ifr.ifr_name, ifname);
int fd, ret;
fd = socket(AF_UNIX, SOCK_DGRAM, 0);