zebian.log

技術系備忘録とか

コンテナランタイムを自作した

コンテナの仕組みを勉強したかったため、Goでコンテナランタイムを自作した。雑実装だし未実装の機能もたくさんあるが、ある程度形になってきたため現状をまとめる。

リポジトリ

github.com

プロジェクト名から和の雰囲気を感じるが、これはリポジトリ名をkombu(昆布)にしたかったため、せっかくなら今回は和風で固めようと思ったから。趣があっていいんじゃないでしょうか。

dashiが自作コンテナランタイムだが、nimonoとyaminabeは実験的な要素で、セキュキャン2023でコンテナを使ったマルウェアサンドボックスを実装した経験があり、今回はその再実装を自作コンテナランタイムでやりたいなと思ったので実装している。言語としてGoを選択した理由は、Goを書いたことがなかったということと、コンテナを扱うOSSがGoで実装されている事例が多く見受けられたため。実際OCI(後述)のリファレンス実装でGoが使われており、ライブラリとしてそのまま使うことができたのでよかった。

コンテナを動かすために必要な技術

container-security.dev www.publickey1.jp

コンテナの仕組みを学ぶうえでこれらのサイトがとても役に立った。

低レベルランタイムと高レベルランタイム

コンテナランタイムは大きく分けて2種類あり、それぞれ役割分担しながらコンテナを実現している。

  • 低レベルランタイム - 実際にLinuxの機能を呼び出してコンテナを起動する(例:runC、gVisor)
  • 高レベルランタイム - コンテナイメージの管理などをしている(例:containerd)
Open Container Initiative (OCI)

www.opencontainers.org コンテナの技術仕様を標準化する組織。ランタイムやコンテナイメージの仕様を標準化している。Runtime Specification、Image Specification、Distribution Specificationといった仕様がある。コンテナソフトウェアといえばDockerが有名だが、DockerはこのOCIに準拠するにあたってソースコードが公開されるようになった。

コンテナイメージ

コンテナ環境をパッケージ化したもので、設定ファイル、ファイルシステムバンドルなどが含まれている。

Namespace

Linuxカーネルの機能で、Namespaceの内と外でシステムリソースを分離する。ネットワーク、ファイルシステム、PIDなどそれぞれ分離することができる。ファイルシステム、PIDを分離することによって、Namespaceの内側から外側のプロセスに干渉することができなくなる。コンテナの肝。

chroot, pivot_root

どちらもルートディレクト/を別のディレクトリにすげ替える機能。各コンテナ向けに用意されたrootfsに切り替えるために用いる。chrootができる権限を持っていると簡単にコンテナエスケープできてしまうため、代わりにpivot_rootを利用したほうが安全。

cgroup

プロセスをグループ化し、そのグループに属するプロセスに対してリソースの制限を行う機能。CPU使用率、メモリ使用量など細かく制限することができる。

Capability

Linuxにおける権限の仕組みで、ファイルやプロセスに対して権限を設定する。例えば先述のchrootができる権限、ネットワーク通信ができる権限、プロセスをKillできる権限など、様々な種類がある。特権を持っていなくても、特定の権限を経由してコンテナエスケープすることができてしまうものもあるため、過剰な権限の付与は危険。

Seccomp

特定のシステムコールの実行を禁止する機能。Capabilityの制限を突破されてもSeccompによって防ぐことができる。

コンテナランタイムの実装

dashiはCLIツールとして実装したので、コマンドを入力して操作する。当初は低レベルランタイムという立ち位置で開発をしていたが、この段階ではまだ役割を分けるメリットが特にないため、1つのバイナリとして実装した。

[_____@archlinux kombu]$ ./build/dashi
Usage: dashi <flags> <subcommand> <subcommand args>

Subcommands:
        commands         list all command names
        create           create new container
        delete           delete container
        download         download docker image and convert to OCI runtime bundle
        init             container's init process
        preinit          pre initialize container
        start            start container
downloadコマンド

指定されたDockerイメージをダウンロードし、OCIランタイムバンドル(Filesystem Bundle)に変換するコマンド。ここでは実装をサボっていて、内部でskopeoとumociを呼び出しているだけなので、これらのツールを事前にインストールする必要がある。ダウンロードと変換が完了すると、./bundles以下にバンドルが配置される。

[_____@archlinux kombu]$ ls -l ./bundles
total 8
drwx------ 3 root  root  4096 Jun 27 09:58 busybox-latest
drwx------ 3 root root 4096 May 16 17:12 ubuntu-latest

[_____@archlinux kombu]$ sudo ls -l ./bundles/busybox-latest
total 80
-rw-r--r--  1 root root  2967 Jun 27 09:58 config.json
drwxr-xr-x 11 root root  4096 May 19  2023 rootfs
-rw-r--r--  1 root root 66026 Jun 27 09:58 sha256_50aa4698fa6262977cff89181b2664b99d8a56dbca847bf62f2ef04854597cf8.mtree
-rw-r--r--  1 root root   372 Jun 27 09:58 umoci.json

このconfig.jsonに記述された設定に基づき、コンテナの設定・起動を行う。config.jsonの仕様はここで読むことができる

start/preinit/initコマンド

createコマンドでバンドルを指定してコンテナを作成することに成功すると、./containers/<CONTAINER NAME>以下にバンドルの中身がコピーされる。その後startコマンドでコンテナを起動することができる。

[_____@archlinux kombu]$ sudo ./build/dashi start test
2024/06/27 10:22:08 DEBU Received request from child req=get_cid
2024/06/27 10:22:08 DEBU Received request from child req=get_init_opt
2024/06/27 10:22:08 DEBU Mounted source=proc dest=./containers/test/rootfs/proc
2024/06/27 10:22:08 DEBU Mounted source=tmpfs dest=./containers/test/rootfs/dev
2024/06/27 10:22:08 DEBU Mounted source=devpts dest=./containers/test/rootfs/dev/pts
2024/06/27 10:22:08 DEBU Mounted source=shm dest=./containers/test/rootfs/dev/shm
2024/06/27 10:22:08 DEBU Mounted source=mqueue dest=./containers/test/rootfs/dev/mqueue
2024/06/27 10:22:08 DEBU Mounted source=sysfs dest=./containers/test/rootfs/sys
2024/06/27 10:22:08 DEBU Mounted source=cgroup2 dest=./containers/test/rootfs/sys/fs/cgroup
2024/06/27 10:22:08 DEBU Received request from child req=send_mount_list
2024/06/27 10:22:08 DEBU Set UID uid=0
2024/06/27 10:22:08 DEBU Set GID gid=0
2024/06/27 10:22:08 DEBU Set root path=./containers/test/rootfs
2024/06/27 10:22:08 DEBU Set cwd cwd=/
2024/06/27 10:22:08 DEBU Set env env="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
2024/06/27 10:22:08 DEBU Set env env="TERM=xterm"
2024/06/27 10:22:08 DEBU Set env env="HOME=/root"
2024/06/27 10:22:08 DEBU Set hostname hostname=umoci-default
2024/06/27 10:22:08 DEBU Set rlimits
2024/06/27 10:22:08 DEBU Set capabilities caps="{Effective:536871968 Permitted:536871968 Inheritable:536871968}"
2024/06/27 10:22:08 INFO Start container... args=[/bin/bash]

root@umoci-default:/# uname -a
Linux umoci-default 6.8.7-arch1-1 #1 SMP PREEMPT_DYNAMIC Wed, 17 Apr 2024 15:20:28 +0000 x86_64 x86_64 x86_64 GNU/Linux

root@umoci-default:/# ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0 1226956 4888 ?        Sl   01:22   0:00 ./build/dashi init
root           6  0.0  0.0   4588  3712 ?        S    01:22   0:00 /bin/bash
root          10  0.0  0.0   7888  3968 ?        R+   01:22   0:00 ps aux

root@umoci-default:/# exit
exit
2024/06/27 10:29:57 DEBU Received request from child req=unmount
2024/06/27 10:29:57 DEBU Unmounted dest=./containers/test/rootfs/sys/fs/cgroup
2024/06/27 10:29:57 DEBU Unmounted dest=./containers/test/rootfs/dev/pts
2024/06/27 10:29:57 DEBU Unmounted dest=./containers/test/rootfs/dev/shm
2024/06/27 10:29:57 DEBU Unmounted dest=./containers/test/rootfs/dev/mqueue
2024/06/27 10:29:57 DEBU Unmounted dest=./containers/test/rootfs/proc
2024/06/27 10:29:57 DEBU Unmounted dest=./containers/test/rootfs/dev
2024/06/27 10:29:57 DEBU Unmounted dest=./containers/test/rootfs/sys
2024/06/27 10:29:57 DEBU Received request from child req=close_con

[_____@archlinux kombu]$

Ubuntuのイメージを使った例だと、デフォルトでconfig.jsonに記述されているbashが呼び出される。psコマンドで確認するとしっかりPID分離が行われており、コンテナの内側からホストのプロセスに触れなくなっていることがわかる。

startコマンド実行からの処理の流れを図にした。

startコマンドを呼び出したあと、preinitコマンドをバックグラウンドで呼び出し、ソケット通信を行いながらコンテナの初期化処理を進めている。preinitコマンドを呼び出す段階でNamespace分離を行っている。GoではCloneflagsを設定するだけで分離することができるため便利。

preinitコマンドを呼び出すコード(dashi/cmd/start.go

cmd := exec.Command(os.Args[0], "preinit")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.SysProcAttr = c.SpecSysProcAttr()
cmd.ExtraFiles = []*os.File{cSock.F}
if err := cmd.start(); err != nil {
    log.Error("Error occured", "err", err)
    return subcommands.ExitFailure
}

c.SpecSysProcAttr()でconfig.jsonのNamespaceの設定(linux.namespaces)を読み取り、CloneFlagsにパースしている。

preinitコマンド(dashi/cmd/preinit.go

...

if err := c.Init(&opt); err != nil {
    log.Error("Failed to initialize container", "err", err)
    return subcommands.ExitFailure
}

log.Info("Starting container...", "args", opt.Args)
if err := syscall.Exec("/proc/self/exe", []string{"/proc/self/exe", "init"}, os.Environ()); err != nil {
    log.Error("Failed to exec init", "err", err)
    return subcommands.ExitFailure
}

// unreachable here
return subcommands.ExitSuccess

c.Init()で現在のプロセスに対してconfig.jsonの各種設定を反映する。設定完了後にinitコマンドを呼び出しているが、preinitコマンドの呼び出し時と違い、execシステムコールを行い、プロセスを上書きしている。また、chrootを実行したあとであるため、os.Args[0]の代わりに/proc/self/exeを利用して自分自身を呼び出している。

dashi/cmd/init.go

...
// call program
cmd := exec.Command(opt.Args[0], opt.Args[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

// socket connection check
go func() {
    pingReqBytes, _ := internal.RequestToBytes("ping")
    for range ticker.C {
        cSock.Write(pingReqBytes)
    }
}()

if err := cmd.Run(); err != nil {
    log.Warn("Exit status was not 0", "err", err)
}

return subcommands.ExitSuccess

initコマンドでは逆にpreinitコマンドの呼び出し時と同じようにexec.Commandで対象のプログラムを呼び出している。対象のプログラムの実行中、バックグラウンドでソケット通信による10秒間隔の疎通確認を行っている。initコマンドが終了する前に疎通が途切れると、ゾンビプロセスになったと判断して対象のプログラムのプロセスをKillする(未実装)。

特権コンテナ/非特権コンテナ

sudoをつけて実行すると特権コンテナが起動し、そうでなければ非特権コンテナが起動する。非特権コンテナでは権限の関係でコンテナの初期化の設定方法が変わるため、config.jsonの設定を非特権用に書き換える処理が追加されている。この処理はruncのコードを参考にした(というかほぼパクリ)。

まだ未実装の機能
  • cgroup
  • Seccomp
    • デバッグに使用しているUbuntuランタイムバンドルのconfig.jsonにSeccompの項目がなかったため、未検証
  • pivot_root
  • ゾンビプロセスの自動Kill
    • PIDがNamespaceによって分離されているため、プロセスの特定ができない
    • どうしようか考え中
  • コンテナ内でのネットワーク通信
Capability、設定が剥がれてる疑惑
root@umoci-default:/# ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.4  0.0 1227208 4628 ?        Sl   01:30   0:00 /proc/self/exe init
root           9  0.0  0.0   4588  3840 ?        S    01:30   0:00 /bin/bash
root          12 50.0  0.0   7888  3968 ?        R+   01:30   0:00 ps aux
root@umoci-default:/# cat /proc/1/status | grep Cap
CapInh: 0000000020000420
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
root@umoci-default:/# cat /proc/9/status | grep Cap
CapInh: 0000000020000420
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000

本来ならばCapPrmCapEffCapInhと同じ値になっている必要があるが000001ffffffffff、つまり全許可になってしまっている。こういう表記になっているが、非特権コンテナではホストユーザーと同じ権限で動いている(mknod /dev/nullができなかった)?要検証。

マルウェアサンドボックスの実装

現状自作コンテナランタイムをサンドボックス環境として利用するにはあまりにもセキュリティがお粗末過ぎると思っているが、せっかくなので紹介する。

このマルウェアサンドボックスは指定したプログラムを自作コンテナランタイムで動いているコンテナ内で実行し、実行中に呼ばれたシステムコールのログを収集する。ログを解析し、あらかじめ定義しておいた検知ルールに違反していることがわかったら、その違反しているルールを出力する。振る舞い検知だけでマルウェアかどうか判断することはできないため、あくまで「違反している」という体にしている。

システムコールロガーについては前回の記事で書いたので、それを参考にしてほしい。 zebian.hatenablog.com

[_____@archlinux kombu]$ python3 ./task.py task_run

...

./build/yaminabe -t ./target_programs/remove_root/target/debug/remove_root -d ./detection_rules
[2024-07-04T02:23:40Z INFO  yaminabe::sandbox] Created mount directory
[2024-07-04T02:23:42Z INFO  yaminabe::sandbox] Execute runner script...
[2024-07-04T02:23:42Z INFO  yaminabe::wrapper] Running command in the container: ["sh", "/mnt/runner.sh"]
2024/07/04 11:23:45 DEBU Mounted source=proc dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/proc
2024/07/04 11:23:45 DEBU Mounted source=tmpfs dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/dev
2024/07/04 11:23:45 DEBU Mounted source=devpts dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/dev/pts
2024/07/04 11:23:45 DEBU Mounted source=shm dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/dev/shm
2024/07/04 11:23:45 DEBU Mounted source=mqueue dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/dev/mqueue
2024/07/04 11:23:45 DEBU Mounted source=sysfs dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/sys
2024/07/04 11:23:45 DEBU Mounted source=cgroup2 dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/sys/fs/cgroup
2024/07/04 11:23:45 DEBU Mounted source=mount-22042023-b8d0-48e1-836e-381c56384f3d dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/mnt
2024/07/04 11:23:45 DEBU Set UID uid=0
2024/07/04 11:23:45 DEBU Set GID gid=0
2024/07/04 11:23:45 DEBU Set root path=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs
2024/07/04 11:23:45 DEBU Set cwd cwd=/
2024/07/04 11:23:45 DEBU Set env env="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
2024/07/04 11:23:45 DEBU Set env env="TERM=xterm"
2024/07/04 11:23:45 DEBU Set env env="HOME=/root"
2024/07/04 11:23:45 DEBU Set hostname hostname=umoci-default
2024/07/04 11:23:45 DEBU Set rlimits
2024/07/04 11:23:45 DEBU Set capabilities caps="{Effective:536871968 Permitted:536871968 Inheritable:536871968}"
2024/07/04 11:23:45 INFO Start container... args="[sh /mnt/runner.sh]"
2024/07/04 02:23:45 Loaded BPF binary
2024/07/04 02:23:45 Loaded BPF object
2024/07/04 02:23:45 Attached hook function
removed successfully!
2024/07/04 02:23:46 Successed to export log
2024/07/04 11:23:46 DEBU Unmounted dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/sys/fs/cgroup
2024/07/04 11:23:46 DEBU Unmounted dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/dev/pts
2024/07/04 11:23:46 DEBU Unmounted dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/dev/shm
2024/07/04 11:23:46 DEBU Unmounted dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/dev/mqueue
2024/07/04 11:23:46 DEBU Unmounted dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/proc
2024/07/04 11:23:46 DEBU Unmounted dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/dev
2024/07/04 11:23:46 DEBU Unmounted dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/sys
2024/07/04 11:23:46 DEBU Unmounted dest=./containers/22042023-b8d0-48e1-836e-381c56384f3d/rootfs/mnt
2024/07/04 11:23:46 INFO Exited container
[2024-07-04T02:23:46Z INFO  yaminabe] violation detected!
[2024-07-04T02:23:46Z INFO  yaminabe] violated detection rule: DetectionRule { meta: Meta { name: "Sample rule", desc: "This is the sample rule" }, syscall: Some(Syscall { blacklist_numbers: [], frequent: [SyscallFrequent { threshold_count: 10, number: 59 }, SyscallFrequent { threshold_count: 4, number: 263 }], consecutive: [SyscallConsecutive { threshold_count: 4, number: 1 }] }), timestamp: Some(Timestamp { check_timetravel: true }) }
[2024-07-04T02:23:46Z INFO  yaminabe] message: "Frequent syscall detected: 263"
[2024-07-04T02:23:46Z INFO  yaminabe::sandbox] Removed mount directory

この例では、検体プログラムであるremove_rootが検知ルール「Sample rule」に違反しており、理由が「システムコール263番(renameat)が4回以上呼ばれた」ということがわかる。

detection_rules/sample.toml

[meta]
name = "Sample rule"
desc = "This is the sample rule"

[syscall]
# 指定のシステムコールが実行されていたら検知
#blacklist_numbers = [0, 1, 2, 3] # read, write, open, close
blacklist_numbers = []


# 頻繁に実行されるシステムコールを監視
[[syscall.frequent]]
# 検体の実行中にexecveの実行が10回を超えたら検知
threshold_count = 10
number = 59 # execve

[[syscall.frequent]]
threshold_count = 4
number = 263 # renameat

# 連続で実行されるシステムコールを監視
[[syscall.consecutive]]
# 連続でwriteが4回実行されたら検知
threshold_count = 4
number = 1

[timestamp]
# タイムスタンプが過去や未来に飛んだら(改ざんされたら)検知
check_timetravel = true

他にもいくつか検知項目を用意している。現在の実装ではOR条件になっているが、AND条件にする機能もあったほうがいいかもしれない。

システムコールロガーの問題点

システムコールロガーをコンテナ内で動かすことにおいて色々問題が発生したのでまとめる。

  • 非特権コンテナでBPFを実行できない
2024/05/30 18:36:45 Loaded BPF binary
2024/05/30 18:36:45 Failed to load BPF object: field HookX64SysCall: program hook_x64_sys_call: load BTF: BTF not supported (requires >= v4.18)

非特権環境で実行しようとするとと、このようにBTF not supportedと出力されて実行ができない。 docs.redhat.com このドキュメントによると、そもそも非特権環境では権限不足で動かないっぽい?

  • NamespaceでPID分離しているにもかかわらずホストのログが出力される

先述の通り非特権コンテナでは動かせないため、仕方なく特権コンテナで動かすことにした。

uptime: 0d 2:40:20:733.963.236, syscall: Some(Write), pid: 528, ppid: 483, comm: "node"
uptime: 0d 2:40:20:734.122.348, syscall: Some(Signalfd), pid: 528, ppid: 483, comm: "node"
uptime: 0d 2:40:20:734.173.862, syscall: Some(Signalfd), pid: 528, ppid: 483, comm: "node"
uptime: 0d 2:40:20:734.174.852, syscall: Some(Signalfd), pid: 528, ppid: 483, comm: "node"
uptime: 0d 2:40:20:734.185.193, syscall: Some(Shutdown), pid: 483, ppid: 479, comm: "node"
uptime: 0d 2:40:20:734.303.354, syscall: Some(Signalfd), pid: 483, ppid: 479, comm: "node"
uptime: 0d 2:40:20:734.304.845, syscall: Some(Signalfd), pid: 483, ppid: 479, comm: "node"
uptime: 0d 2:40:20:735.832.16, syscall: Some(Write), pid: 483, ppid: 479, comm: "node"
uptime: 0d 2:40:20:735.921.956, syscall: Some(Signalfd), pid: 483, ppid: 479, comm: "node"
uptime: 0d 2:40:20:735.923.555, syscall: Some(Signalfd), pid: 483, ppid: 479, comm: "node"
uptime: 0d 2:40:20:735.996.357, syscall: Some(Sendmsg), pid: 4754, ppid: 4735, comm: "tokio-runtime-w"
uptime: 0d 2:40:20:736.17.280, syscall: Some(SchedSetaffinity), pid: 4754, ppid: 4735, comm: "tokio-runtime-w"
uptime: 0d 2:40:20:736.22.692, syscall: Some(Signalfd), pid: 4754, ppid: 4735, comm: "tokio-runtime-w"
uptime: 0d 2:40:20:736.34.108, syscall: Some(Recvfrom), pid: 4754, ppid: 4735, comm: "code-5437499feb"
uptime: 0d 2:40:20:736.56.631, syscall: Some(SchedSetaffinity), pid: 4754, ppid: 4735, comm: "code-5437499feb"
uptime: 0d 2:40:20:736.64.799, syscall: Some(RtSigprocmask), pid: 4734, ppid: 4730, comm: "sshd"
uptime: 0d 2:40:20:736.69.315, syscall: Some(Read), pid: 4734, ppid: 4730, comm: "sshd"
uptime: 0d 2:40:20:736.79.392, syscall: Some(MemfdCreate), pid: 4734, ppid: 4730, comm: "sshd"
uptime: 0d 2:40:20:736.84.872, syscall: Some(RtSigprocmask), pid: 4734, ppid: 4730, comm: "sshd"
uptime: 0d 2:40:20:736.85.999, syscall: Some(Unshare), pid: 4734, ppid: 4730, comm: "sshd"
uptime: 0d 2:40:20:736.87.25, syscall: Some(RtSigprocmask), pid: 4734, ppid: 4730, comm: "sshd"
uptime: 0d 2:40:20:736.88.445, syscall: Some(Write), pid: 4734, ppid: 4730, comm: "sshd"
uptime: 0d 2:40:20:736.234.531, syscall: Some(RtSigprocmask), pid: 4734, ppid: 4730, comm: "sshd"
uptime: 0d 2:40:20:736.236.305, syscall: Some(Unshare), pid: 4734, ppid: 4730, comm: "sshd"
uptime: 0d 2:40:20:736.747.483, syscall: Some(Signalfd), pid: 9010, ppid: 9009, comm: "dashi"
uptime: 0d 2:40:20:736.749.506, syscall: Some(Getitimer), pid: 9010, ppid: 9009, comm: "dashi"

...

uptime: 0d 2:40:21:484.391.457, syscall: Some(Mmap), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.399.799, syscall: Some(Pipe), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.405.923, syscall: Some(Mkdirat), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.409.664, syscall: Some(Fstat), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.410.670, syscall: Some(Mmap), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.413.295, syscall: Some(Close), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.415.789, syscall: Some(Mkdirat), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.418.95, syscall: Some(Read), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.423.978, syscall: Some(Fstat), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.424.722, syscall: Some(Mmap), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.426.179, syscall: Some(Mmap), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.430.605, syscall: Some(Mmap), pid: 9038, ppid: 9024, comm: "target"
uptime: 0d 2:40:21:484.432.719, syscall: Some(Mmap), pid: 9038, ppid: 9024, comm: "target"
...

収集されたログを見れば分かる通り、コンテナ内には存在しないプロセスのログが存在するし、pid、ppidもホストから見たものになっている。この問題は前にも遭遇したことがあるため予想はしていたが、BPFプログラムはカーネルレベルで動いているため、これはおそらく仕様。本当は良くないが、仕方ないのでプロセス名「target」でフィルターをかけた。BPF、結構便利だけど若干融通が効かない場面がある。