Ubuntu Weekly Recipe

第695回 入門BPF CO-RE

この記事を読むのに必要な時間:およそ 10.5 分

文字列処理の追加

第690回ではPIDとPPIDだけでなく,execve()を呼び出したプログラム名(COMM)と,その引数である実行予定のファイル名(FNAME)も表示していました。これにも対応してみましょう。ここまでの内容を理解していたら,そこまで難しくはないでしょう。

まずexecsnoop.hにデータ送受信用のメンバーであるcommfnameを追加します。今回は単なる固定長の文字列です。commのほうはカーネルのタスク構造体に合わせたサイズにし,fnameのほうは適当な長さに決めました。

#define TASK_COMM_LEN 16 /* from linux/sched.h */

struct event {
    pid_t pid;
    pid_t ppid;
    char comm[TASK_COMM_LEN];
    char fname[32];
};

BPFプログラムであるexecsnoop.bpf.cは,データを取得するAPIを呼ぶだけです。

int syscalls__execve(struct trace_event_raw_sys_enter *ctx)
    (中略)

    if (bpf_get_current_comm(&event->comm, sizeof(event->comm)) < 0)
        goto err;

    if (bpf_core_read_user_str(event->fname, sizeof(event->fname), (const char*)ctx->args[0]) < 0)
        goto err;

    bpf_ringbuf_submit(event, 0);

    return 0;

err:
    bpf_ringbuf_discard(event, 0);
    return 0;

bpf_get_current_comm()はBCCでも使っていたAPIがそのまま使えます。bpf_core_read_user_str()は初出ですが,使い方自体はbpf_probe_read_user_str()と同じで,指定した文字列変数にユーザー空間のアドレスにある文字列をコピーしてくれるだけです※2⁠。また_strで終わるAPIはNULL終端されていることが保証されます。ctx->args[0]execve()の第一引数という意味です。

※2
bpf_core_read_user_str()は内部でbpf_probe_read_user_str()を呼び出しています。

どちらのAPIも失敗時には負の値が返ってきます。そこでその際は何もせずに確保したバッファーをbpf_ringbuf_discard()だけの処理にしました。

ユーザーランドプログラムであるexecsnoop.cのほうは,受け取った結果をただ表示するだけです。

    /* データの出力側 */
    fprintf(stdout, "% 8d  % 8d  %-16s  %-32s\n", event->pid, event->ppid, event->comm, event->fname);

    /* 実行時に最初に表示されるヘッダー */
    fprintf(stdout, "%-8s  %-8s  %-16s  %-32s\n", "PID", "PPID", "COMM", "FNAME");

このあたりは好みに合わせて調整してください。毎度のことながら,実際にビルドして実行しみましょう。リポジトリではv1.4タグを付けています。

$ git checkout r695/4 v1.4
$ make
$ sudo ./execsnoop
PID       PPID      COMM              FNAME
  547716      2276  tmux: server      /bin/sh
  547717    547716  sh                /usr/bin/byobu-status
  547718      2276  tmux: server      /bin/sh
  547719    547717  byobu-status      /usr/bin/sed
  547720    547718  sh                /usr/bin/byobu-status

これでほぼBCC/Python版だった第690回と同じ出力結果になりました。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。