Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: Use only nftw for file tree parsing

The bpftool sources include code to walk file trees, but use multiple
frameworks to do so: nftw and fts. While nftw conforms to POSIX/SUSv3 and
is widely available, fts is not conformant and less common, especially on
non-glibc systems. The inconsistent framework usage hampers maintenance
and portability of bpftool, in particular for embedded systems.

Standardize code usage by rewriting one fts-based function to use nftw and
clean up some related function warnings by extending use of "const char *"
arguments. This change helps in building bpftool against musl for OpenWrt.

Also fix an unsafe call to dirname() by duplicating the string to pass,
since some implementations may directly alter it. The same approach is
used in libbpf.c.

Signed-off-by: Tony Ambardar <Tony.Ambardar@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/bpf/20200721024817.13701-1-Tony.Ambardar@gmail.com

authored by

Tony Ambardar and committed by
Daniel Borkmann
9165e1d7 8fca4f98

+85 -62
+83 -60
tools/bpf/bpftool/common.c
··· 1 1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 2 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 3 3 4 + #define _GNU_SOURCE 4 5 #include <ctype.h> 5 6 #include <errno.h> 6 7 #include <fcntl.h> 7 - #include <fts.h> 8 + #include <ftw.h> 8 9 #include <libgen.h> 9 10 #include <mntent.h> 10 11 #include <stdbool.h> ··· 162 161 return err; 163 162 } 164 163 165 - int open_obj_pinned(char *path, bool quiet) 164 + int open_obj_pinned(const char *path, bool quiet) 166 165 { 167 - int fd; 166 + char *pname; 167 + int fd = -1; 168 168 169 - fd = bpf_obj_get(path); 170 - if (fd < 0) { 169 + pname = strdup(path); 170 + if (!pname) { 171 171 if (!quiet) 172 - p_err("bpf obj get (%s): %s", path, 173 - errno == EACCES && !is_bpffs(dirname(path)) ? 174 - "directory not in bpf file system (bpffs)" : 175 - strerror(errno)); 176 - return -1; 172 + p_err("mem alloc failed"); 173 + goto out_ret; 177 174 } 178 175 176 + fd = bpf_obj_get(pname); 177 + if (fd < 0) { 178 + if (!quiet) 179 + p_err("bpf obj get (%s): %s", pname, 180 + errno == EACCES && !is_bpffs(dirname(pname)) ? 181 + "directory not in bpf file system (bpffs)" : 182 + strerror(errno)); 183 + goto out_free; 184 + } 185 + 186 + out_free: 187 + free(pname); 188 + out_ret: 179 189 return fd; 180 190 } 181 191 182 - int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type) 192 + int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type) 183 193 { 184 194 enum bpf_obj_type type; 185 195 int fd; ··· 380 368 jsonw_end_array(json_wtr); 381 369 } 382 370 371 + /* extra params for nftw cb */ 372 + static struct pinned_obj_table *build_fn_table; 373 + static enum bpf_obj_type build_fn_type; 374 + 375 + static int do_build_table_cb(const char *fpath, const struct stat *sb, 376 + int typeflag, struct FTW *ftwbuf) 377 + { 378 + struct bpf_prog_info pinned_info; 379 + __u32 len = sizeof(pinned_info); 380 + struct pinned_obj *obj_node; 381 + enum bpf_obj_type objtype; 382 + int fd, err = 0; 383 + 384 + if (typeflag != FTW_F) 385 + goto out_ret; 386 + 387 + fd = open_obj_pinned(fpath, true); 388 + if (fd < 0) 389 + goto out_ret; 390 + 391 + objtype = get_fd_type(fd); 392 + if (objtype != build_fn_type) 393 + goto out_close; 394 + 395 + memset(&pinned_info, 0, sizeof(pinned_info)); 396 + if (bpf_obj_get_info_by_fd(fd, &pinned_info, &len)) 397 + goto out_close; 398 + 399 + obj_node = calloc(1, sizeof(*obj_node)); 400 + if (!obj_node) { 401 + err = -1; 402 + goto out_close; 403 + } 404 + 405 + obj_node->id = pinned_info.id; 406 + obj_node->path = strdup(fpath); 407 + if (!obj_node->path) { 408 + err = -1; 409 + free(obj_node); 410 + goto out_close; 411 + } 412 + 413 + hash_add(build_fn_table->table, &obj_node->hash, obj_node->id); 414 + out_close: 415 + close(fd); 416 + out_ret: 417 + return err; 418 + } 419 + 383 420 int build_pinned_obj_table(struct pinned_obj_table *tab, 384 421 enum bpf_obj_type type) 385 422 { 386 - struct bpf_prog_info pinned_info = {}; 387 - struct pinned_obj *obj_node = NULL; 388 - __u32 len = sizeof(pinned_info); 389 423 struct mntent *mntent = NULL; 390 - enum bpf_obj_type objtype; 391 424 FILE *mntfile = NULL; 392 - FTSENT *ftse = NULL; 393 - FTS *fts = NULL; 394 - int fd, err; 425 + int flags = FTW_PHYS; 426 + int nopenfd = 16; 427 + int err = 0; 395 428 396 429 mntfile = setmntent("/proc/mounts", "r"); 397 430 if (!mntfile) 398 431 return -1; 399 432 433 + build_fn_table = tab; 434 + build_fn_type = type; 435 + 400 436 while ((mntent = getmntent(mntfile))) { 401 - char *path[] = { mntent->mnt_dir, NULL }; 437 + char *path = mntent->mnt_dir; 402 438 403 439 if (strncmp(mntent->mnt_type, "bpf", 3) != 0) 404 440 continue; 405 - 406 - fts = fts_open(path, 0, NULL); 407 - if (!fts) 408 - continue; 409 - 410 - while ((ftse = fts_read(fts))) { 411 - if (!(ftse->fts_info & FTS_F)) 412 - continue; 413 - fd = open_obj_pinned(ftse->fts_path, true); 414 - if (fd < 0) 415 - continue; 416 - 417 - objtype = get_fd_type(fd); 418 - if (objtype != type) { 419 - close(fd); 420 - continue; 421 - } 422 - memset(&pinned_info, 0, sizeof(pinned_info)); 423 - err = bpf_obj_get_info_by_fd(fd, &pinned_info, &len); 424 - if (err) { 425 - close(fd); 426 - continue; 427 - } 428 - 429 - obj_node = malloc(sizeof(*obj_node)); 430 - if (!obj_node) { 431 - close(fd); 432 - fts_close(fts); 433 - fclose(mntfile); 434 - return -1; 435 - } 436 - 437 - memset(obj_node, 0, sizeof(*obj_node)); 438 - obj_node->id = pinned_info.id; 439 - obj_node->path = strdup(ftse->fts_path); 440 - hash_add(tab->table, &obj_node->hash, obj_node->id); 441 - 442 - close(fd); 443 - } 444 - fts_close(fts); 441 + err = nftw(path, do_build_table_cb, nopenfd, flags); 442 + if (err) 443 + break; 445 444 } 446 445 fclose(mntfile); 447 - return 0; 446 + return err; 448 447 } 449 448 450 449 void delete_pinned_obj_table(struct pinned_obj_table *tab)
+2 -2
tools/bpf/bpftool/main.h
··· 152 152 int get_fd_type(int fd); 153 153 const char *get_fd_type_name(enum bpf_obj_type type); 154 154 char *get_fdinfo(int fd, const char *key); 155 - int open_obj_pinned(char *path, bool quiet); 156 - int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type); 155 + int open_obj_pinned(const char *path, bool quiet); 156 + int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type); 157 157 int mount_bpffs_for_pin(const char *name); 158 158 int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***)); 159 159 int do_pin_fd(int fd, const char *name);