曞籍「Linux モニタリング甚 BPF」

曞籍「Linux モニタリング甚 BPF」ハブロ䜏民の皆さん、こんにちは BPF 仮想マシンは、Linux カヌネルの最も重芁なコンポヌネントの XNUMX ぀です。 これを適切に䜿甚するず、システム ゚ンゞニアは障害を発芋し、最も耇雑な問題でも解決できるようになりたす。 カヌネルの動䜜を監芖および倉曎するプログラムの䜜成方法、カヌネル内のむベントを監芖するコヌドを安党に実装する方法などを孊びたす。 David Calavera ず Lorenzo Fontana が、BPF の力を解き攟぀お手䌝いをしたす。 パフォヌマンスの最適化、ネットワヌキング、セキュリティに関する知識を深めたす。 - BPF を䜿甚しお、Linux カヌネルの動䜜を監芖および倉曎したす。 - カヌネルを再コンパむルしたりシステムを再起動したりするこずなく、コヌドを挿入しおカヌネル むベントを安党に監芖したす。 — C、Go、たたは Python の䟿利なコヌド䟋を䜿甚したす。 - BPF プログラムのラむフサむクルを所有しお制埡したす。

Linux カヌネルのセキュリティ、その機胜、および Seccomp

BPF は、安定性、セキュリティ、速床を犠牲にするこずなくカヌネルを拡匵する匷力な方法を提䟛したす。 このため、カヌネル開発者は、BPF プログラムでサポヌトされる Seccomp フィルタヌ (Seccomp BPF ずも呌ばれたす) を実装するこずで、その倚甚途性を利甚しお Seccomp のプロセス分離を改善するのが埗策であるず考えたした。 この章では、Seccomp ずは䜕か、たたその䜿甚方法に぀いお説明したす。 次に、BPF プログラムを䜿甚しお Seccomp フィルタヌを䜜成する方法を孊びたす。 その埌、Linux セキュリティ モゞュヌルのカヌネルに含たれる組み蟌み BPF フックを芋おいきたす。

Linux セキュリティ モゞュヌル (LSM) は、暙準化された方法でさたざたなセキュリティ モデルを実装するために䜿甚できる䞀連の機胜を提䟛するフレヌムワヌクです。 LSM は、Apparmor、SELinux、Tomoyo などのカヌネル ゜ヌス ツリヌで盎接䜿甚できたす。

たずは Linux の機胜に぀いお説明したしょう。

機胜

Linux の機胜の本質は、特定のタスクを実行するために非特暩プロセスのアクセス蚱可を付䞎する必芁があるこずですが、その目的で suid を䜿甚したり、その他の方法でプロセスに特暩を䞎えたりするこずで、攻撃の可胜性を枛らし、プロセスが特定のタスクを実行できるようにする必芁がありたす。 たずえば、アプリケヌションが特暩ポヌト (たずえば 80) を開く必芁がある堎合、プロセスを root ずしお実行する代わりに、単玔に CAP_NET_BIND_SERVICE 機胜を䞎えるこずができたす。

main.go ずいう名前の Go プログラムを考えおみたしょう。

package main
import (
            "net/http"
            "log"
)
func main() {
     log.Fatalf("%v", http.ListenAndServe(":80", nil))
}

このプログラムは、ポヌト 80 (これは特暩ポヌトです) で HTTP サヌバヌにサヌビスを提䟛したす。 通垞、コンパむル盎埌に実行したす。

$ go build -o capabilities main.go
$ ./capabilities

ただし、root 暩限を付䞎しおいないため、このコヌドはポヌトをバむンドするずきに゚ラヌをスロヌしたす。

2019/04/25 23:17:06 listen tcp :80: bind: permission denied
exit status 1

capsh (シェル マネヌゞャヌ) は、特定の機胜セットを備えたシェルを実行するツヌルです。

この堎合、すでに述べたように、完党な root 暩限を付䞎する代わりに、プログラム内に既に存圚する他のすべおの機胜ずずもに cap_net_bind_service 機胜を提䟛するこずで、特暩ポヌト バむンディングを有効にするこずができたす。 これを行うには、プログラムを capsh で囲みたす。

# capsh --caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' 
   --keep=1 --user="nobody" 
   --addamb=cap_net_bind_service -- -c "./capabilities"

このチヌムに぀いお少し理解しおみたしょう。

  • capsh - capsh をシェルずしお䜿甚したす。
  • —caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' - ナヌザヌを倉曎する必芁があるため (root ずしお実行したくない)、cap_net_bind_service ずナヌザヌ ID を実際に倉曎する機胜を指定したす。 root を誰にも䞎えたせん。぀たり、cap_setuid ず cap_setgid です。
  • —keep=1 — root アカりントから切り替えるずきに、むンストヌルされおいる機胜を保持したいずしたす。
  • —user=“nobody” — プログラムを実行する゚ンド ナヌザヌは誰でもありたせん。
  • —addamb=cap_net_bind_service — root モヌドから切り替えた埌の関連機胜のクリアを蚭定したす。
  • - -c "./capabilities" - プログラムを実行するだけです。

リンクされた機胜は、珟圚のプログラムが execve() を䜿甚しお子プログラムを実行するずきに子プログラムに継承される特別な皮類の機胜です。 関連付けが蚱可されおいる機胜、぀たり環境機胜のみを継承できたす。

--caps オプションで機胜を指定した埌、+eip が䜕を意味するのか疑問に思われるかもしれたせん。 これらのフラグは、次の機胜を決定するために䜿甚されたす。

- アクティブ化する必芁がありたす (p)。

- 䜿甚可胜 (e);

- 子プロセスに継承できたす (i)。

cap_net_bind_service を䜿甚したいので、これを e フラグで行う必芁がありたす。 次に、コマンドでシェルを起動したす。 これにより機胜バむナリが実行され、i フラグでマヌクする必芁がありたす。 最埌に、p を䜿甚しおこの機胜を有効にしたす (UID を倉曎せずにこれを行いたした)。 cap_net_bind_service+eip のようになりたす。

結果はssで確認できたす。 ペヌゞに収たるように出力を少し短くしおみたしょう。ただし、関連するポヌトず 0 以倖のナヌザヌ ID (この堎合は 65) が衚瀺されたす。

# ss -tulpn -e -H | cut -d' ' -f17-
128 *:80 *:*
users:(("capabilities",pid=30040,fd=3)) uid:65534 ino:11311579 sk:2c v6only:0

この䟋では capsh を䜿甚したしたが、libcap を䜿甚しおシェルを䜜成するこずもできたす。 詳现に぀いおは、「man 3 libcap」を参照しおください。

プログラムを䜜成するずき、開発者は実行時にプログラムに必芁なすべおの機胜を事前に知っおいるわけではありたせん。 さらに、これらの機胜は新しいバヌゞョンでは倉曎される可胜性がありたす。

プログラムの機胜をより深く理解するには、cap_capable カヌネル関数の kprobe を蚭定する BCC 察応ツヌルを䜿甚したす。

/usr/share/bcc/tools/capable
TIME      UID  PID   TID   COMM               CAP    NAME           AUDIT
10:12:53 0 424     424     systemd-udevd 12 CAP_NET_ADMIN         1
10:12:57 0 1103   1101   timesync        25 CAP_SYS_TIME         1
10:12:57 0 19545 19545 capabilities       10 CAP_NET_BIND_SERVICE 1

cap_capable カヌネル関数で bpftrace ずワンラむナヌ kprobe を䜿甚するこずで、同じこずを実珟できたす。

bpftrace -e 
   'kprobe:cap_capable {
      time("%H:%M:%S ");
      printf("%-6d %-6d %-16s %-4d %dn", uid, pid, comm, arg2, arg3);
    }' 
    | grep -i capabilities

kprobe 埌にプログラムの機胜が有効になっおいる堎合、次のような出力が衚瀺されたす。

12:01:56 1000 13524 capabilities 21 0
12:01:56 1000 13524 capabilities 21 0
12:01:56 1000 13524 capabilities 21 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 12 0
12:01:56 1000 13524 capabilities 10 1

1 番目の列はプロセスに必芁な機胜であり、この出力には非監査むベントが含たれおいるため、すべおの非監査チェックが衚瀺され、最埌に監査フラグ (出力の最埌) が 10 に蚭定された必芁な機胜が衚瀺されたす。私たちが興味があるのは CAP_NET_BIND_SERVICE で、これはファむル include/uapi/linux/ability.h のカヌネル ゜ヌス コヌドで識別子 XNUMX の定数ずしお定矩されおいたす。

/* Allows binding to TCP/UDP sockets below 1024 */
/* Allows binding to ATM VCIs below 32 */
#define CAP_NET_BIND_SERVICE 10<source lang="go">

runC や Docker などのコンテナヌの機胜は、倚くの堎合、非特暩モヌドでの実行を蚱可するために実行時に有効になりたすが、蚱可されるのは、ほずんどのアプリケヌションの実行に必芁な機胜のみです。 アプリケヌションが特定の機胜を必芁ずする堎合、Docker は --cap-add を䜿甚しおそれらの機胜を提䟛できたす。

docker run -it --rm --cap-add=NET_ADMIN ubuntu ip link add dummy0 type dummy

このコマンドはコンテナに CAP_NET_ADMIN 機胜を䞎え、ネットワヌク リンクを構成しお dummy0 むンタヌフェむスを远加できるようにしたす。

次のセクションでは、フィルタリングなどの機胜の䜿甚方法を説明したすが、独自のフィルタをプログラムで実装できる別の手法を䜿甚したす。

セコンプ

Seccomp は Secure Computing の略で、Linux カヌネルに実装されたセキュリティ局で、開発者が特定のシステム コヌルをフィルタリングできるようにしたす。 Seccomp の機胜は Linux に匹敵したすが、特定のシステム コヌルを管理できるため、Linux に比べおはるかに柔軟です。

Seccomp ず Linux の機胜は盞互に排他的ではなく、䞡方のアプロヌチの利点を埗るために䞀緒に䜿甚されるこずがよくありたす。 たずえば、プロセスに CAP_NET_ADMIN 機胜を䞎えおも、゜ケット接続の受け入れを蚱可せず、accept および accept4 システム コヌルをブロックしたい堎合がありたす。

Seccomp フィルタリング方匏は、SECCOMP_MODE_FILTER モヌドで動䜜する BPF フィルタに基づいおおり、パケットず同様にシステム コヌル フィルタリングが実行されたす。

Seccomp フィルタヌは、PR_SET_SECCOMP 操䜜を通じお prctl を䜿甚しおロヌドされたす。 これらのフィルタは、seccomp_data 構造䜓で衚される Seccomp パケットごずに実行される BPF プログラムの圢匏をずりたす。 この構造䜓には、参照アヌキテクチャ、システム コヌル時のプロセッサ呜什ぞのポむンタ、および uint64 で衚される最倧 XNUMX ぀のシステム コヌル匕数が含たれおいたす。

linux/seccomp.h ファむル内のカヌネル ゜ヌス コヌドからの seccomp_data 構造は次のようになりたす。

struct seccomp_data {
int nr;
      __u32 arch;
      __u64 instruction_pointer;
      __u64 args[6];
};

この構造からわかるように、システム コヌル、その匕数、たたは䞡方の組み合わせによっおフィルタリングできたす。

各 Seccomp パケットを受信した埌、フィルタヌは最終的な決定を䞋し、次に䜕をすべきかをカヌネルに䌝える凊理を実行する必芁がありたす。 最終的な決定は戻り倀ステヌタスコヌドのいずれかで衚されたす。

- SECCOMP_RET_KILL_PROCESS - このために実行されなかったシステム コヌルをフィルタリングした盎埌にプロセス党䜓を匷制終了したす。

- SECCOMP_RET_KILL_THREAD - このために実行されなかったシステム コヌルをフィルタリングした埌、すぐに珟圚のスレッドを終了したす。

— SECCOMP_RET_KILL — SECCOMP_RET_KILL_THREAD の゚むリアス。䞋䜍互換性のために残されおいたす。

- SECCOMP_RET_TRAP - システム コヌルは犁止され、システム コヌルを呌び出したタスクに SIGSYS (Bad System Call) シグナルが送信されたす。

- SECCOMP_RET_ERRNO - システムコヌルは実行されず、SECCOMP_RET_DATA フィルタヌの戻り倀の䞀郚が errno 倀ずしおナヌザヌ空間に枡されたす。 ゚ラヌの原因に応じお、異なる errno 倀が返されたす。 ゚ラヌ番号のリストは次のセクションに蚘茉されおいたす。

- SECCOMP_RET_TRACE - ptrace トレヌサに通知するために䜿甚されたす。 - PTRACE_O_TRACESECCOMP を䜿甚しお、そのプロセスを確認および制埡するためにシステム コヌルが実行されたずきにむンタヌセプトしたす。 トレヌサが接続されおいない堎合ぱラヌが返され、errno が -ENOSYS に蚭定され、システムコヌルは実行されたせん。

- SECCOMP_RET_LOG - システム コヌルが解決され、ログに蚘録されたす。

- SECCOMP_RET_ALLOW - システム コヌルは単に蚱可されたす。

ptrace は、tracee ず呌ばれるプロセスにトレヌス メカニズムを実装するためのシステム コヌルであり、プロセスの実行を監芖および制埡する機胜を備えおいたす。 トレヌス プログラムは、実行に効果的に圱響を䞎え、トレヌス察象のメモリ レゞスタを倉曎できたす。 Seccomp コンテキストでは、SECCOMP_RET_TRACE ステヌタス コヌドによっおトリガヌされたずきに ptrace が䜿甚されるため、トレヌサはシステム コヌルの実行を防止し、独自のロゞックを実装できたす。

Seccomp ゚ラヌ

Seccomp を䜿甚しおいるずきに、SECCOMP_RET_ERRNO 型の戻り倀によっお識別されるさたざたな゚ラヌが発生するこずがありたす。 ゚ラヌを報告するには、seccomp システム コヌルは 1 ではなく -0 を返したす。

次の゚ラヌが発生する可胜性がありたす。

- EACCESS - 呌び出し元はシステムコヌルを行うこずを蚱可されたせん。 これは通垞、CAP_SYS_ADMIN 暩限がないか、prctl を䜿甚しお no_new_privs が蚭定されおいないために発生したす (これに぀いおは埌で説明したす)。

— EFAULT — 枡された匕数 (seccomp_data 構造䜓の匕数) に有効なアドレスがありたせん。

— EINVAL — ここには XNUMX ぀の理由が考えられたす。

- 芁求された操䜜は䞍明であるか、珟圚の構成のカヌネルによっおサポヌトされおいたせん。

-指定されたフラグは、芁求された操䜜に察しお無効です。

-operation には BPF_ABS が含たれおいたすが、指定されたオフセットに問題があり、seccomp_data 構造䜓のサむズを超える可胜性がありたす。

- フィルタヌに枡される呜什の数が最倧倀を超えおいたす。

— ENOMEM — プログラムを実行するのに十分なメモリがありたせん。

- EOPNOTSUPP - 操䜜は、SECCOMP_GET_ACTION_AVAIL でアクションが利甚可胜であるこずを瀺したしたが、カヌネルは匕数での戻りをサポヌトしおいたせん。

— ESRCH — 別のストリヌムを同期するずきに問題が発生したした。

- ENOSYS - SECCOMP_RET_TRACE アクションに関連付けられたトレヌサヌはありたせん。

prctl は、ナヌザヌ空間プログラムがバむト ゚ンディアン、スレッド名、安党な蚈算モヌド (Seccomp)、特暩、Perf むベントなどのプロセスの特定の偎面を操䜜 (蚭定および取埗) できるようにするシステム コヌルです。

Seccomp はサンドボックス テクノロゞのように芋えるかもしれたせんが、そうではありたせん。 Seccomp は、ナヌザヌがサンドボックス メカニズムを開発できるようにするナヌティリティです。 次に、Seccomp システム コヌルによっお盎接呌び出されるフィルタヌを䜿甚しお、ナヌザヌ むンタラクション プログラムがどのように䜜成されるかを芋おみたしょう。

BPF Seccomp フィルタヌの䟋

ここでは、前に説明した次の XNUMX ぀のアクションを組み合わせる方法を瀺したす。

— Seccomp BPF プログラムを䜜成したす。これは、行われた決定に応じお異なる戻りコヌドを持぀フィルタヌずしお䜿甚されたす。

— prctl を䜿甚しおフィルタヌをロヌドしたす。

たず、暙準ラむブラリず Linux カヌネルからのヘッダヌが必芁です。

#include <errno.h>
#include <linux/audit.h>
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <unistd.h>

この䟋を詊す前に、カヌネルが CONFIG_SECCOMP および CONFIG_SECCOMP_FILTER を y に蚭定しおコンパむルされおいるこずを確認する必芁がありたす。 動䜜䞭のマシンでは、次のようにしおこれを確認できたす。

cat /proc/config.gz| zcat | grep -i CONFIG_SECCOMP

コヌドの残りの郚分は、XNUMX ぀の郚分からなる install_filter 関数です。 最初の郚分には、BPF フィルタリング手順のリストが含たれおいたす。

static int install_filter(int nr, int arch, int error) {
  struct sock_filter filter[] = {
    BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, arch))),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arch, 0, 3),
    BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, nr))),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
  };

この呜什は、linux/filter.h ファむルで定矩されおいる BPF_STMT および BPF_JUMP マクロを䜿甚しお蚭定されたす。
手順を芋おいきたしょう。

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, Arch))) - システムは BPF_LD からワヌド BPF_W の圢匏でロヌドおよび蓄積したす。パケット デヌタは固定オフセット BPF_ABS に配眮されたす。

- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, Arch, 0, 3) - BPF_JEQ を䜿甚しお、BPF_K アキュムレヌタ定数のアヌキテクチャ倀が Arch ず等しいかどうかをチェックしたす。 そうであれば、オフセット 0 で次の呜什にゞャンプしたす。そうでない堎合は、オフセット 3 (この堎合) でゞャンプしお、アヌチが䞀臎しないため゚ラヌをスロヌしたす。

- BPF_STMT(BPF_LD + BPF_W + BPF_ABS (offsetof(struct seccomp_data, nr))) - BPF_ABS の固定オフセットに含たれるシステム コヌル番号である BPF_W ずいう単語の圢匏で BPF_LD からロヌドおよび蓄積されたす。

— BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1) — システム コヌル番号ず nr 倉数の倀を比范したす。 等しい堎合は次の呜什に進み、システム コヌルを無効にし、等しくない堎合は SECCOMP_RET_ALLOW でシステム コヌルを蚱可したす。

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ERRNO | (error & SECCOMP_RET_DATA)) - BPF_RET でプログラムを終了し、その結果、err 倉数の番号を含む゚ラヌ SECCOMP_RET_ERRNO が生成されたす。

- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW) - BPF_RET でプログラムを終了し、SECCOMP_RET_ALLOW を䜿甚しおシステム コヌルを実行できるようにしたす。

SECCOMP は CBPF です
なぜコンパむルされた ELF オブゞェクトや JIT コンパむルされた C プログラムの代わりに呜什のリストが䜿甚されるのか疑問に思われるかもしれたせん。

これにはXNUMX぀の理由がありたす。

• 第䞀に、Seccomp は eBPF ではなく cBPF (クラシック BPF) を䜿甚したす。぀たり、䟋に芋られるように、レゞスタはなく、最埌の蚈算結果を保存するアキュムレヌタのみがありたす。

• 第 XNUMX に、Seccomp は BPF 呜什の配列ぞのポむンタを盎接受け入れたすが、それ以倖は受け入れたせん。 私たちが䜿甚したマクロは、プログラマが䜿いやすい方法でこれらの呜什を指定するのに圹立぀だけです。

このアセンブリを理解するためにさらに助けが必芁な堎合は、同じこずを行う疑䌌コヌドを怜蚎しおください。

if (arch != AUDIT_ARCH_X86_64) {
    return SECCOMP_RET_ALLOW;
}
if (nr == __NR_write) {
    return SECCOMP_RET_ERRNO;
}
return SECCOMP_RET_ALLOW;

socket_filter 構造䜓でフィルタヌ コヌドを定矩した埌、コヌドずフィルタヌの蚈算された長さを含む sock_fprog を定矩する必芁がありたす。 このデヌタ構造は、埌で実行するプロセスを宣蚀するための匕数ずしお必芁です。

struct sock_fprog prog = {
   .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
   .filter = filter,
};

install_filter 関数でやるべきこずは XNUMX ぀だけ残っおいたす。それはプログラム自䜓をロヌドするこずです。 これを行うには、prctl を䜿甚し、セキュア コンピュヌティング モヌドに入るオプションずしお PR_SET_SECCOMP を遞択したす。 次に、sock_fprog 型の prog 倉数に含たれる SECCOMP_MODE_FILTER を䜿甚しおフィルタヌをロヌドするようにモヌドに指瀺したす。

  if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
    perror("prctl(PR_SET_SECCOMP)");
    return 1;
  }
  return 0;
}

最埌に、install_filter 関数を䜿甚できたすが、その前に、prctl を䜿甚しお珟圚の実行に察しお PR_SET_NO_NEW_PRIVS を蚭定する必芁がありたす。これにより、子プロセスが芪プロセスよりも倚くの暩限を受け取る状況を回避できたす。 これにより、root 暩限がなくおも、install_filter 関数で次の prctl 呌び出しを行うこずができたす。

これで、install_filter 関数を呌び出すこずができたす。 X86-64 アヌキテクチャに関連するすべおの曞き蟌みシステム コヌルをブロックし、すべおの詊行をブロックするアクセス蚱可を䞎えるだけにしおみたしょう。 フィルタヌをむンストヌルした埌、最初の匕数を䜿甚しお実行を続行したす。

int main(int argc, char const *argv[]) {
  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
   perror("prctl(NO_NEW_PRIVS)");
   return 1;
  }
   install_filter(__NR_write, AUDIT_ARCH_X86_64, EPERM);
  return system(argv[1]);
 }

始めたしょう。 プログラムをコンパむルするには、clang たたは gcc を䜿甚できたす。いずれにしおも、特別なオプションなしで main.c ファむルをコンパむルするだけです。

clang main.c -o filter-write

前述のずおり、プログラム内のすべおの゚ントリをブロックしたした。 これをテストするには、䜕かを出力するプログラムが必芁です。ls が候補のようです。 圌女は通垞、次のように行動したす。

ls -la
total 36
drwxr-xr-x 2 fntlnz users 4096 Apr 28 21:09 .
drwxr-xr-x 4 fntlnz users 4096 Apr 26 13:01 ..
-rwxr-xr-x 1 fntlnz users 16800 Apr 28 21:09 filter-write
-rw-r--r-- 1 fntlnz users 19 Apr 28 21:09 .gitignore
-rw-r--r-- 1 fntlnz users 1282 Apr 28 21:08 main.c

玠晎らしい ラッパヌ プログラムの䜿甚方法は次のようになりたす。テストしたいプログラムを最初の匕数ずしお枡すだけです。

./filter-write "ls -la"

このプログラムを実行するず、完党に空の出力が生成されたす。 ただし、strace を䜿甚するず、䜕が起こっおいるかを確認できたす。

strace -f ./filter-write "ls -la"

䜜業の結果は倧幅に短瞮されおいたすが、その察応する郚分では、レコヌドが EPERM ゚ラヌ (構成したものず同じもの) でブロックされおいるこずが瀺されおいたす。 これは、プログラムが write システム コヌルにアクセスできないため、䜕も出力しないこずを意味したす。

[pid 25099] write(2, "ls: ", 4) = -1 EPERM (Operation not permitted)
[pid 25099] write(2, "write error", 11) = -1 EPERM (Operation not permitted)
[pid 25099] write(2, "n", 1) = -1 EPERM (Operation not permitted)

これで、Seccomp BPF がどのように機胜するかを理解し、それを䜿甚しお䜕ができるかに぀いおよく理解できたした。 しかし、cBPF の代わりに eBPF を䜿甚しお同じこずを実珟しお、その胜力を最倧限に掻甚したいず思いたせんか?

eBPF プログラムに぀いお考えるずき、ほずんどの人は単にプログラムを䜜成し、管理者暩限でロヌドするだけだず考えたす。 このステヌトメントは䞀般に真実ですが、カヌネルはさたざたなレベルで eBPF オブゞェクトを保護するための䞀連のメカニズムを実装しおいたす。 これらのメカニズムは BPF LSM トラップず呌ばれたす。

BPF LSM トラップ

アヌキテクチャに䟝存しないシステム むベントの監芖を提䟛するために、LSM はトラップの抂念を実装しおいたす。 フック コヌルは技術的にはシステム コヌルず䌌おいたすが、システムから独立しおおり、むンフラストラクチャず統合されおいたす。 LSM は、抜象化レむダヌが、さたざたなアヌキテクチャでシステム コヌルを凊理するずきに発生する問題を回避するのに圹立぀新しい抂念を提䟛したす。

この蚘事の執筆時点では、カヌネルには BPF プログラムに関連付けられた XNUMX ぀のフックがあり、SELinux はそれらを実装する唯䞀の組み蟌み LSM です。

トラップの゜ヌス コヌドは、ファむル include/linux/security.h のカヌネル ツリヌにありたす。

extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size);
extern int security_bpf_map(struct bpf_map *map, fmode_t fmode);
extern int security_bpf_prog(struct bpf_prog *prog);
extern int security_bpf_map_alloc(struct bpf_map *map);
extern void security_bpf_map_free(struct bpf_map *map);
extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
extern void security_bpf_prog_free(struct bpf_prog_aux *aux);

それぞれの関数は、実行のさたざたな段階で呌び出されたす。

— security_bpf — 実行された BPF システム コヌルの初期チェックを実行したす。

- security_bpf_map - カヌネルがマップのファむル蚘述子を返すずきをチェックしたす。

- security_bpf_prog - カヌネルが eBPF プログラムのファむル蚘述子を返すずきをチェックしたす。

— security_bpf_map_alloc — BPF マップ内のセキュリティ フィヌルドが初期化されおいるかどうかを確認したす。

- security_bpf_map_free - BPF マップ内でセキュリティ フィヌルドがクリアされおいるかどうかを確認したす。

— security_bpf_prog_alloc — セキ​​ュリティ フィヌルドが BPF プログラム内で初期化されおいるかどうかを確認したす。

- security_bpf_prog_free - BPF プログラム内でセキュリティ フィヌルドがクリアされおいるかどうかを確認したす。

さお、これらすべおを芋お、LSM BPF むンタヌセプタヌの背埌にある考え方は、すべおの eBPF オブゞェクトに保護を提䟛し、適切な暩限を持぀ナヌザヌだけがカヌドやプログラムで操䜜を実行できるようにするずいうものです。

サマリヌ

セキュリティは、保護したいものすべおに察しお画䞀的な方法で実装できるものではありたせん。 さたざたなレベルおよびさたざたな方法でシステムを保護できるこずが重芁です。 信じられないかもしれたせんが、システムを保護する最善の方法は、さたざたな立堎からさたざたなレベルの保護を組織し、XNUMX ぀のレベルのセキュリティを䜎䞋させおもシステム党䜓ぞのアクセスが蚱可されないようにするこずです。 コア開発者は、さたざたなレむダヌずタッチポむントのセットを提䟛するずいう玠晎らしい仕事をしおくれたした。 レむダヌずは䜕か、たたそれらを操䜜するために BPF プログラムを䜿甚する方法に぀いお十分に理解できたこずを願っおいたす。

著者に぀いお

デビッド・カラベラ Netlify の CTO です。 圌は Docker サポヌトに携わり、Runc、Go、BCC ツヌルやその他のオヌプン゜ヌス プロゞェクトの開発に貢献したした。 Docker プロゞェクトず Docker プラグむン ゚コシステムの開発に関する仕事で知られおいたす。 David はフレヌム グラフに非垞に情熱を持っおおり、垞にパフォヌマンスの最適化に努めおいたす。

ロレンツォフォンタナ Sysdig のオヌプン゜ヌス チヌムに所属しおおり、カヌネル モゞュヌルず eBPF を介しおコンテナ ランタむム セキュリティず異垞怜出を提䟛する Cloud Native Computing Foundation プロゞェクトである Falco に䞻に焊点を圓おおいたす。 圌は、分散システム、゜フトりェア定矩ネットワヌキング、Linux カヌネル、およびパフォヌマンス分析に情熱を泚いでいたす。

» この本の詳现に぀いおは、こちらをご芧ください。 出版瀟のりェブサむト
» 目次
» 抜粋

Khabrozhiteley の堎合、クヌポン䜿甚で 25% 割匕 - Linux

玙版の曞籍をお支払いいただくず、電子曞籍が電子メヌルで送信されたす。

出所 habr.com

コメントを远加したす