Skip to content

Commit

Permalink
Replace usage of bcc_elf_is_*() functions
Browse files Browse the repository at this point in the history
In the long term, the project wants to get rid of the bcc dependency. As
another step towards achieving this goal, replace the usage of
bcc_elf_is_*() functions with implementations based directly on libelf.
The bcc layer doesn't really add any value here.

In resolve_binary_path(), we benefit additionally from not unnecessarily
opening the file in question and reading its ELF header twice, if it
does not reference an executable.
  • Loading branch information
d-e-s-o authored and ajor committed Jun 25, 2024
1 parent e942bf2 commit 19df2b1
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/bpftrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ int BPFtrace::add_probe(const ast::AttachPoint &ap,
// Preload symbol tables if necessary
if (resources.probes_using_usym.find(&p) !=
resources.probes_using_usym.end() &&
bcc_elf_is_exe(ap.target.c_str())) {
is_exe(ap.target)) {
auto user_symbol_cache_type = config_.get(
ConfigKeyUserSymbolCacheType::default_);
// preload symbol table for executable to make it available even if the
Expand Down
76 changes: 73 additions & 3 deletions src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <link.h>
#include <map>
#include <memory>
#include <optional>
#include <regex>
#include <sstream>
#include <string>
Expand Down Expand Up @@ -867,6 +868,70 @@ std::vector<std::string> resolve_binary_path(const std::string &cmd, int pid)
}
}

/*
Check whether 'path' refers to a ELF file. Errors are swallowed silently and
result in return of 'nullopt'. On success, the ELF type (e.g., ET_DYN) is
returned.
*/
static std::optional<int> is_elf(const std::string &path)
{
int fd;
Elf *elf;
void *ret;
GElf_Ehdr ehdr;
std::optional<int> result = {};

if (elf_version(EV_CURRENT) == EV_NONE) {
return result;
}

fd = open(path.c_str(), O_RDONLY, 0);
if (fd < 0) {
return result;
}

elf = elf_begin(fd, ELF_C_READ, NULL);
if (elf == NULL) {
goto err_close;
}

if (elf_kind(elf) != ELF_K_ELF) {
goto err_close;
}

ret = (void *)gelf_getehdr(elf, &ehdr);
if (ret == NULL) {
goto err_end;
}

result = ehdr.e_type;

err_end:
(void)elf_end(elf);
err_close:
(void)close(fd);
return result;
}

static bool has_exec_permission(const std::string &path)
{
using std::filesystem::perms;

auto perms = std::filesystem::status(path).permissions();
return (perms & perms::owner_exec) != perms::none;
}

/*
Check whether 'path' refers to an executable ELF file.
*/
bool is_exe(const std::string &path)
{
if (auto e_type = is_elf(path)) {
return e_type == ET_EXEC && has_exec_permission(path);
}
return false;
}

/*
Private interface to resolve_binary_path, used for the exposed variants above,
allowing for a PID whose mount namespace should be optionally considered.
Expand All @@ -891,9 +956,14 @@ static std::vector<std::string> resolve_binary_path(const std::string &cmd,
rel_path = path_for_pid_mountns(pid, path);
else
rel_path = path;
if (bcc_elf_is_exe(rel_path.c_str()) ||
bcc_elf_is_shared_obj(rel_path.c_str()))
valid_executable_paths.push_back(rel_path);

// Both executables and shared objects are game.
if (auto e_type = is_elf(rel_path)) {
if ((e_type == ET_EXEC && has_exec_permission(rel_path)) ||
e_type == ET_DYN) {
valid_executable_paths.push_back(rel_path);
}
}
}

return valid_executable_paths;
Expand Down
1 change: 1 addition & 0 deletions src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ bool is_compile_time_func(const std::string &func_name);
bool is_supported_lang(const std::string &lang);
bool is_type_name(std::string_view str);
std::string exec_system(const char *cmd);
bool is_exe(const std::string &path);
std::vector<std::string> resolve_binary_path(const std::string &cmd);
std::vector<std::string> resolve_binary_path(const std::string &cmd, int pid);
std::string path_for_pid_mountns(int pid, const std::string &path);
Expand Down

0 comments on commit 19df2b1

Please sign in to comment.