eBPF:符号“function_name”:不满足的程序引用

问题描述 投票:0回答:1

我有用于使用跟踪点跟踪 execve 的 ebpf 代码:

#define EXECVE_COMM_LENGTH 1024
#define EXECVE_ARGS_COUNT 100
#define EXECVE_ARG_SIZE 20
#define DEFAULT_SUB_BUF_LEN 16
#define DEFAULT_SUB_BUF_SIZE 255

struct p_exec_program_event
{
    u64 ktime;
    u32 pid;
    u8 filename[EXECVE_COMM_LENGTH];
    u8 args[EXECVE_ARGS_COUNT][EXECVE_ARG_SIZE];
    u8 pwd[DEFAULT_SUB_BUF_LEN][DEFAULT_SUB_BUF_SIZE];
};

inline int read_dentry_strings(struct dentry *dentry, u8 buf[DEFAULT_SUB_BUF_LEN][DEFAULT_SUB_BUF_SIZE])
{
    struct dentry *curr_dtry = dentry;
    struct dentry *lastdtryp = dentry;
    unsigned int i = 0;

    if (buf)
    {
        bpf_probe_read_str(buf[i], DEFAULT_SUB_BUF_SIZE, BPF_CORE_READ(curr_dtry, d_name.name)); //  problems start here
        for (i = 1; i < DEFAULT_SUB_BUF_LEN; i++)
        {
            struct dentry *parent =  BPF_CORE_READ(curr_dtry, d_parent);
            if (parent != lastdtryp)
            {
                lastdtryp = parent;
                curr_dtry = parent;
                bpf_probe_read_str(buf[i], DEFAULT_SUB_BUF_SIZE, BPF_CORE_READ(curr_dtry, d_name.name));
            }
            else
                break;
        }
    }

    return 0;
}

inline int read_argv(const char *const *argv, u8 args[EXECVE_ARGS_COUNT][EXECVE_ARG_SIZE])
{
    for (int i = 1; i < EXECVE_ARGS_COUNT; i++)
    {
        char arg[EXECVE_ARG_SIZE];
        void *curr_arg = (void *)&argv[i];
        if (curr_arg != NULL)
        {
            const char *argp = NULL;
            bpf_probe_read_user(&argp, sizeof(argp), curr_arg);
            if (argp != NULL)
            {
                bpf_probe_read_user_str(args[i - 1], EXECVE_ARG_SIZE, (void *)argp);
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }
    }
    return 0;
}

inline int handle_execveat(char *filename, const char *const *argv)
{
    struct p_exec_program_event *event_info;

    if (!filename || !argv)
    {
        return 0;
    }

    event_info = bpf_ringbuf_reserve(&p_exec_program_events, sizeof(struct p_exec_program_event), 0);
    if (!event_info)
    {
        return 0;
    }

    event_info->ktime = bpf_ktime_get_ns();
    event_info->pid = bpf_get_current_pid_tgid();

    long res = bpf_probe_read_user_str(event_info->filename, sizeof(event_info->filename), filename);
    if (res)
    {
        if (event_info->filename[0] == '.')
        {
            struct task_struct *task = (struct task_struct *)bpf_get_current_task();
            struct dentry *dentry = BPF_CORE_READ(task, fs, pwd.dentry);
            read_dentry_strings(dentry, event_info->pwd);
        }
        // else -> absolute path in filename already resolved
    }

    read_argv(argv, event_info->args);

    bpf_ringbuf_submit(event_info, 0);

    return 0;
}

SEC("tracepoint/syscalls/sys_enter_execve")
int sys_enter_execve(struct enter_execve_info *ctx)
{
    return handle_execveat(ctx->filename, ctx->argv);
}

当我运行此代码时,我收到错误消息:

2023/12/27 21:41:28 Loading objects: field SysEnterExecve: program sys_enter_execve: Call at insn 36: symbol "handle_execveat": unsatisfied program reference

exit status 1

你能帮我理解 read_dentry_strings 中的代码(或根本代码中)有什么问题吗?

我正在使用 ebpf2go(github 上的最新版本)

我对代码进行了实验,发现问题出在 read_dentry_strings 中 - 无需调用此函数,程序就可以正常工作。我开始注释所有行,发现当我调用

bpf_probe_read_str(buf[i], DEFAULT_SUB_BUF_SIZE, BPF_CORE_READ(curr_dtry, d_name.name));

时出现错误
linux clang ebpf
1个回答
0
投票

TL;DR. 该错误表明函数

handle_execveat
未内联。您可以使用
__attribute__((always_inline))
确保编译器将内联它。


错误说明

2023/12/27 21:41:28 加载对象:字段 SysEnterExecve:程序 sys_enter_execve:在 insn 36 处调用:符号“handle_execveat”:不满足的程序引用

此错误意味着加载程序(在您的例子中为 cilium/ebpf)尝试解析函数调用中的符号

handle_execveat

BPF 到 BPF 函数调用是可能的(有限制),但考虑到使用

inline
,这可能不是您想要实现的目标。因此我们可以得出结论,
handle_execveat
没有按预期内联。

强制内联

创建一个函数

inline
实际上并不能保证编译器会内联它。使函数
static
增加了编译器实际内联它的机会。标记它
__attribute__((always_inline))
确保它会内联。

© www.soinside.com 2019 - 2024. All rights reserved.