本文の内容は、2022年10月31日にJason Andressが投稿したブログ(https://sysdig.com/blog/kernel-parameters-falco/)を元に日本語に翻訳・再構成した内容となっております。
ユーザーは、太陽の光が降り注ぐ世界、それが現実だと自分たちが信じている世界、に住んでいます。しかし、そこには目に見えない裏の世界があります。同じように現実的でありながら、それほど明るく照らされていない場所。それがカーネル・パラメータ側です(ジョージ・ロメロに謝意を表する)。
カーネルパラメータは、実際にはそれほど怖いものではありませんが、Linux の世界では暗くてクモの巣だらけのコーナーになることがあります。カーネルパラメータは、Linux(あるいは Unix 系)カーネルにパラメータを渡して、カーネ ルの振る舞いを制御するための手段です。これらのパラメータを変更することで、メモリ、ネットワーク、ファイルシステムなど、かなり多くの異なるものの動作を制御することができます。
カーネルのパラメータは非常に多く、2,000近くあります。
Linux/Unixの様々なフレーバーで、異なるパラメータを見つけることができます。例えば、様々なクラウドプロバイダーなど、特定の環境で使用されたり、強調されたりするパラメータもあります。多くの場合、これらのパラメータを表示または更新するために、まもなくその使用方法を説明するsysctlユーティリティが使用されます。また、作業している特定の OS やディストリビューションに応じて、ファイルシステムのさまざまな部分でそれらを見つけることができます。
カーネルパラメータランドスケープを巡る
カーネルパラメータは、ファイルシステムの/proc/sys/
以下に格納されているファイルとして見つけることができます。このディレクトリ構造を見てみると、比較的広範囲に渡っていることが分かります。以下のリストは、ディレクトリ構造の深さが2階層しかありませんが、実際にはここに表示されているディレクトリの下にさらに多くのディレクトリが存在します。
├── abi ├── debug ├── dev │ ├── cdrom │ ├── hpet │ ├── mac_hid │ ├── parport │ ├── raid │ ├── scsi │ └── tty ├── fs │ ├── binfmt_misc │ ├── epoll │ ├── fanotify │ ├── inotify │ ├── mqueue │ ├── quota │ └── verity ├── kernel │ ├── firmware_config │ ├── keys │ ├── pty │ ├── random │ ├── seccomp │ ├── usermodehelper │ └── yama ├── net │ ├── bridge │ ├── core │ ├── fan │ ├── ipv4 │ ├── ipv6 │ ├── mptcp │ ├── netfilter │ └── unix ├── user └── vm
/proc/sys/
の下のトップレベルの構造を見ると、異なるパラメータのセットが何を行うのか、少なくともハイレベルのアイデアを得ることができます。- abi: 実行ドメインとパーソナリティに関するパラメータ
- debug: デバッグ用パラメータ
- dev: システム上のデバイスに関するパラメータ
- fs: ファイルシステムパラメータ
- kernel:カーネルを操作するためのパラメータ
- net: ネットワーキングに関するパラメータ
- user: ユーザーネームスペースパラメータ
- vm: メモリ管理パラメータ
この構造の各ディレクトリは、その下に各パラメータごとにファイル(またはさらにディレクトリ)のセットを持ち、それぞれのファイルには当該パラメータが持つ値が格納されます。
/proc/sys/dev/
以下の構造を見てみると:├── cdrom │ ├── autoclose │ ├── autoeject │ ├── check_media │ ├── debug │ ├── info │ └── lock ├── hpet │ └── max-user-freq ├── mac_hid │ ├── mouse_button2_keycode │ ├── mouse_button3_keycode │ └── mouse_button_emulation ├── parport │ └── default │ ├── spintime │ └── timeslice ├── raid │ ├── speed_limit_max │ └── speed_limit_min ├── scsi │ └── logging_level └── tty └── ldisc_autoload
cdromディレクトリがあり、その下にautocloseというファイルがあることがわかります。これは、dev.cdrom.autocloseカーネル・パラメーターで、まもなく作業することになります。
これらのパラメーターの中には、dev.cdrom.autocloseのように、単純なバイナリ値のものもあります。このパラメータは、1または0のいずれかの値を持ちます。いくつかのパラメータは、広範囲の数値または文字列値を持ちます。dev.cdrom.infoのように奇数であるものもあります。
CD-ROM information, Id: cdrom.c 3.20 2003/12/17 drive name: sr1 sr0 drive speed: 1 1 drive # of slots: 1 1 Can close tray: 1 1 Can open tray: 1 1 Can lock tray: 1 1 Can change speed: 1 1 Can select disk: 0 0 Can read multisession: 1 1 Can read MCN: 1 1 Reports media changed: 1 1 Can play audio: 1 1 Can write CD-R: 1 1 Can write CD-RW: 1 1 Can read DVD: 1 1 Can write DVD-R: 1 1 Can write DVD-RAM: 1 1 Can read MRW: 0 0 Can write MRW: 0 0 Can write RAM: 0 0
インターネット上には、さまざまなカーネルパラメータと、それを変更した場合の影響について、多くの情報があります。特定のパラメータが何を行うかを追跡するための優れたリソースの1つは、Sysctl Explorerです。
カーネルパラメータを使用する
このデモを実行するには、これらのツールを以下の最小バージョンで使用する必要があります。- Ubuntu 22.04
- Falco 0.32.2 (インストールガイド)
これらの例では、Ubuntu 22.04 Jammy Jellyfishを使用する予定です。カーネルパラメータの作業は、Debianベースのほとんどのディストリビューションでは、一般的に以下の例と同じになるはずですが、他のものでは奇妙で素晴らしい方法で異なるかもしれません。
これらのパスのうち最も簡単なのは、sysctl ユーティリティを使用するか、/etc/sysctl.conf にエントリを追加することです。これらのうちいくつかを試してみましょう。cdrom autoclose パラメータは比較的無害で、最近の多くのシステムでも使われていないので、このパラメータと対話することにします。
ライブシステムでカーネルパラメータを操作するために使用できる方法は、かなり多くあります。すべてのLinuxと同様に、与えられたタスクには常に「1つの真実」の方法があります。しかし、ここでは、より一般的な方法をいくつか取り上げます。
カーネルパラメータを見る
パラメータとその値を見るには、sysctl ユーティリティを使って直接問い合わせることができます。sysctl は、特にカーネルパラメータを変更するために作られたツールで、ほとんどの Linux や Unix ライクなオペレーティングシステムで利用可能です。パラメータを直接変更するためには、事前にパラメータ名を知っておく必要があります。
$ sudo sysctl dev.cdrom.autoclose dev.cdrom.autoclose = 1
この結果、dev.cdrom.autocloseが1に設定され、オンになっており、デフォルト値であることがわかります。
パラメータの名前がすぐにわからない場合は、sysctlですべてのパラメータとその値の一覧を取得することもできます。
$ sudo sysctl -a abi.vsyscall32 = 1 debug.exception-trace = 1 debug.kprobes-optimization = 1 dev.cdrom.autoclose = 1 <snip>
私たちが作業しているパラメータは、都合よくリストの先頭の方にありますが、ここには数千個ほどのパラメータがあります。もちろん、何を探しているのかが大体わかっていれば、grep で調べることもできます。
$ sudo sysctl -a | grep cdrom dev.cdrom.autoclose = 1 dev.cdrom.autoeject = 0 dev.cdrom.check_media = 0 dev.cdrom.debug = 0 <snip>
また、ファイルシステムのパラメータファイルを直接見ることもできます。この場合、
/proc/sys/dev/cdrom/autoclose
というファイルです。$ cd /proc/sys/dev/cdrom $ cat autoclose 1
最後に、/etc/sysctl.confをチェックして、ここにパラメータが存在するかどうかを確認します。このファイルには、パラメータが全くないか、コメントアウトされている可能性があります。ほとんどのシステムでは、デフォルトで、このファイルに多くのパラメータはなく、すべてコメントアウトされています。
$ cat /etc/sysctl.conf # # /etc/sysctl.conf - Configuration file for setting system variables # See /etc/sysctl.d/ for additional system variables. # See sysctl.conf (5) for information. # #kernel.domainname = example.com # Uncomment the following to stop low-level messages on console #kernel.printk = 3 4 1 3 <snip>
ここでも、探しているパラメータがまったく存在しないかどうかを確認するために、ファイル内のパラメータを単純にgrepすることができます。
cat /etc/sysctl.conf | grep cdrom
このパラメータはデフォルトで/etc/sysctl.confに存在しないため、変更されていないシステムでここに戻ってくることはありません。
sysctl を使ってカーネルパラメータを更新する
sysctl -w を使って希望の値を書き込むことで、簡単にパラメータの値を編集することができます。この変更は、次にシステムを再起動するまでしか持続しません。$ sudo sysctl -w dev.cdrom.autoclose=0 dev.cdrom.autoclose = 0
この変更をダブルチェックするために、もう一度値をクエリーします。
$ sudo sysctl dev.cdrom.autoclose dev.cdrom.autoclose = 0
sysctl.confを編集してカーネルパラメーターを更新する永続的に変更したい場合は、/etc/sysctl.confにパラメータの変更を追加することができます。
$ sudo bash -c 'echo "dev.cdrom.autoclose = 1" >> /etc/sysctl.conf'
しかし、これだけでは、完全に変更を達成することはできません。今、sysctlでパラメータの状態を確認すると、変更されていないことがわかります。
$ sudo sysctl dev.cdrom.autoclose dev.cdrom.autoclose = 0
ここで、sysctl -p を使って、ファイルから変更内容を読み込む必要があります。ファイルを指定しない場合、sysctl は /etc/sysctl.conf から読み込むと見なしますが、これは私たちが望むことです。その後、再度パラメータを確認し、期待通りの変化を確認することができます。
$ sudo sysctl -p $ sudo sysctl dev.cdrom.autoclose dev.cdrom.autoclose = 1
Note: sysctl が設定ファイルを探す標準的な場所は、他にもいくつかあります: /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf /lib/sysctl.d/*.conf ここでは触れませんが、sysctl.dのmanページには、これらがどのように使われるのかについての情報が豊富に載っています
proc/sys/ 以下のファイルを直接編集して失敗する方法
カーネルパラメータの設定が /proc/sys/ 以下の個々のファイルに格納されていても、一般的にそれらを直接編集することはできません。ファイルを開いて内容を見ることはできますが、変更を加えてファイルに書き込もうとすると、たとえrootであっても、それを実行するための特定の方法に応じて、さまざまなエラーメッセージが表示されるでしょう。vi
"autoclose" E667: Fsync failed
nano
[ Error writing autoclose: Invalid argument ]
cat
bash: autoclose: Permission denied
/proc/
以下の項目は procfs の一部であり、仮想ファイルシステムです。したがって、ここで変更を加えることができたとしても、再起動によって持続することはありません。しかし、これらのファイルの変更を監視することはできますので、すぐに戻ってきます。どのカーネルパラメータに注意を払うべきか?
カーネルパラメータを見るときに難しい問題のひとつは、どのパラメータを気にすべきか整理することです。非常に多くのパラメータがあり、変更可能な設定の範囲も非常に広いのです。どのパラメータが重要で、どのパラメータが予期せぬ変化を見たときにパニックになるべきかを知るにはどうしたらよいのでしょうか。
これは、結論から言うと、本当に答えにくい質問です。ある程度は、使っている特定のOS、ディストリビューション、バージョン、ハードウェアなどに依存します。一方では、カーネルパラメータが変更されるような環境はめったにないと思っていて、変更されたパラメータを見たらいつでも警鐘を鳴らすことが適切かもしれません。一方では、カーネル・パラメータが頻繁に変更される環境もあるかもしれません。クラウドプラットフォームでは、ネットワークなどのインスタンスでカーネルパラメータが調整されることがあります。
もし、セキュリティ対策を超偏執狂モードにしてしまうと、大量のアラートが発生することになります。アラートは、「常に単なるノイズ」であるため、すぐに至極当然に無視されることになりますが、これは明らかに望ましいことではありません。
とはいえ、以下は一般に「重要」とされるパラメータの非網羅的なリストです。
これらはすべて、監視のために特定の環境にランダムに展開したり、設定されているデフォルトから離れた変更を行う前に、慎重にテストされるべきものです。YMMV, IANAD (まあ…), etc…
dev.tty.ldisc_autoload | Disable loading line disciplines for unprivileged users |
fs.protected_fifos fs.protected_hardlinks fs.protected_regular fs.protected_symlinks fs.suid_dumpable | Disable creating files in insecure areas Disable creating hardlinks for unprivileged users Disable creating files in insecure areas Disable creating symlinks for unprivileged users Disable core dumps for elevated processes |
kernel.core_uses_pid kernel.ctrl-alt-del kernel.dmesg_restrict kernel.kptr_restrict kernel.modules_disabled kernel.perf_event_paranoid kernel.randomize_va_space kernel.sysrq kernel.unprivileged_bpf_disabled kernel.yama.ptrace_scope | Block USB devices Disable access to dmesg for unprivileged users Disable kexec to prevent kernel livepatching Restrict access to kernel logs Disable loading kernel modules Restrict use of performance events Address space randomization Harden debugging functionality No BPF for unprivileged users Limit the scope of ptrace |
net.core.bpf_jit_harden | Harden the BPF JIT compiler |
net.ipv4.conf.all.accept_redirects net.ipv4.conf.all.accept_source_route net.ipv4.conf.all.bootp_relay net.ipv4.conf.all.forwarding net.ipv4.conf.all.log_martians net.ipv4.conf.all.mc_forwarding net.ipv4.conf.all.proxy_arp net.ipv4.conf.all.rp_filter net.ipv4.conf.all.send_redirects net.ipv4.conf.default.accept_redirects net.ipv4.conf.default.accept_source_route net.ipv4.conf.default.log_martians net.ipv4.icmp_echo_ignore_broadcasts net.ipv4.icmp_ignore_bogus_error_responses net.ipv4.tcp_syncookies net.ipv4.tcp_timestamps | Disable ICMP redirect acceptance Disable source routing Disable BOOTP relay Disable IP forwarding Disable logging Martian packets Disable multicast routing Harden ARP Source route verification Disable ICMP redirect sending Disable ICMP redirect acceptance Disable source routing Disable logging Martian packets Ignore ICMP echo and timestamp requests from broadcasts Ignore bogus ICMP responses Enable syncookies Protect against time-wait assasination |
net.ipv6.conf.all.accept_redirects net.ipv6.conf.all.accept_source_route net.ipv6.conf.default.accept_redirects net.ipv6.conf.default.accept_source_route | Protect against IP spoofing Protect against man-in-the-middle attacks Protect against IP spoofing Protect against man-in-the-middle attacks |
vm.unprivileged_userfaultfd | Protect against use-after-free |
このほかにも、すぐに感度が上がるわけではありませんが、システム上で変化が見られると不審に思われるカーネルパラメータがあるかもしれません。
この良い例が vm.nr_hugepages パラメータです。このカーネルパラメータは、メモリチャンクの割り当てを変更してメモリ検索を高速化し、暗号通貨マイナーの効率を15~30%向上させることができます。このパラメータがシステム上で不意に変化するのを見ることは、誰かが私たちにマイナーをプレゼントしたことを示す非常に良い指標になるかもしれません。
カーネルパラメータを使って、悪者は何ができるのでしょうか?
一言で言えば、非常に多くのことができます。おそらく、攻撃者はカーネルパラメータを変更するためにシステム上で十分な権限を必要とするか、そうするために他の特権プロセスを転覆させる攻撃をすることになるでしょうが、物事はこれよりもかなり悪くなる可能性があります。
先ほど説明したパラメータの中には、あまり深く掘り下げなくても、ネットワーク攻撃に関連するさまざまな脆弱性を緩和するものがいくつかあります。これらのパラメータの一部または全部を意図的に無効化すると、システムの防御に大きな穴が開く可能性があります。これらは、攻撃者が弄るには本当に醜いパラメータではありません。
例として1つ取り出して、kernel.kexec_load_disabledを考えてみましょう。このパラメータをアンセットすると、実行時に代替カーネルをロードすることができます。単なる置き換えカーネルではなく、どんなカーネルでも、潜在的には完全に無署名のものでさえロードすることができます。いったんカーネルの内容を自由に変更できるようになると、アンチマルウェアのような保護手段や、その他多くのものが、完全に通用しなくなります。
kexecに対する攻撃やkexecを利用した攻撃は、何年も前からモバイル機器やゲーム機の保護を破る定番の方法となっています。このような攻撃を成功させるには、最終的にカーネルパラメータを反転させるよりも少し複雑かもしれませんが、これは攻撃者に出発点としての良い足掛かりを与える可能性があります。
カーネルパラメータへの変更の追跡
実行時に行われる変更のために、私たちのシステムに加えられた変更を監視する必要がある場所は、ありがたいことに、ほとんどありません。
もし、任意のパラメータに加えられた一般的な変更を監視したいのであれば、sysctlツールの使用を監視することができます。このツールは、パラメータを書き込むための -w スイッチと、 /etc/sysctl.conf などのファイルを読み込むための -p スイッチの 2 つが主な用途となります。
幸いなことに、カーネルのパラメータに変更が加えられると、 /proc/sys/
i の下にある変更されるパラメータに関連する個々のファイルも変更されます。dev.cdrom.autoclose に変更を加えると、 /proc/sys/dev/cdrom/autoclose
ファイルが書き込まれます。これは、簡単に追跡できるもので、変更を加える特定のメカニズムを追跡するよりも、少し確実です。また、このメカニズムを使用する場合、どのパラメータの変更を監視したいかをもう少し具体的にすることができます。
では、Falco を使ってこのようなことを行ってみましょう。
カーネルパラメータの変更を追跡するためのFalcoのルールのビルド
Falco をインストールした後、私たちは、Falco ログを簡単に見ることができるように、Falco の設定ファイルに簡単な変更を加えたいと思うでしょう。sudo を使用して /etc/falco/falco.yaml を編集し、以下のようにファイル出力を true に、ファイル名を /var/log/falco_events.log に変更する必要があります。file_output: enabled: true keep_alive: false filename: /var/log/falco_events.log
これが終わったら、ルールのビルドを開始するために、sudoを使ってエディタで/etc/falco/falco_rules.local.yamlを開いていきます。
今後のアップデートや修正を容易にするため、モジュール化されたルールをビルドし、ルールに加えてリストとマクロを実装する予定です。これらの概念の詳細については、Falcoのドキュメントを確認してください。
まず、sensitive_kernel_parameter_filesというリストを追加します。このリストは、監視したいパラメータの特定のファイル名を保持します。この場合、それは
/proc/sys/cdrom/autoclose
です。- list: sensitive_kernel_parameter_files items: [/proc/sys/dev/cdrom/autoclose]
次に、sensitive_kernel_parametersというマクロを追加します。この中に、先ほど作成した sensitive_kernel_parameter_names のリストに現れるファイル記述子名を探す条件を入れます。
- macro: sensitive_kernel_parameters condition: fd.name in (sensitive_kernel_parameter_files)
最後に、Kernel Parameter Modificationというカーネルパラメータの変更を検索する条件を持つルールを作成します。このルールの条件の高速で簡単なルートは、次のようなものでしょう。
condition: (open_write and (fd.name startswith "/proc/sys/" or fd.name startswith "/etc/sysctl"))
この場合、/proc/sys/ または /etc/sysctl の下にあるすべてのファイルへの書き込みを監視することになります。これなら、どんな変更も検出できるでしょ?はい、そうです。
クラウドプロバイダーによっては、特定の環境に最適化するために、インスタンスのカーネルパラメータを変更することがあります。「カーネルパラメータが変更されるたびに通知する」というルールを設定するのは良いアイデアだと思われるかもしれませんが、そうすると大量のノイズを目にする可能性があります(これは経験上の話です)。
その代わりに、もう少し具体的な条件を作ってみましょう。この場合、sensitive_kernel_parameter_filesリストに現れるファイル記述子名を持つ、書き込まれたファイルを監視することにします。
condition: (open_write and sensitive_kernel_parameters)
最終的なルールは、次のようになります:
- rule: Kernel Parameter Modification desc: Detect changes to sensitive kernel parameters. May be an indication of compromise. condition: (open_write and sensitive_kernel_parameters) output: > Sensitive kernel parameter was modified; possible unauthorized changes (user.name=%user.name user.loginuid=%user.loginuid proc.cmdline=%proc.cmdline parent=%proc.pname file=%fd.name container.id=%container.id container_name=%container.name evt.type=%evt.type evt.res=%evt.res proc.pid=%proc.pid proc.cwd=%proc.cwd proc.ppid=%proc.ppid proc.pcmdline=%proc.pcmdline proc.sid=%proc.sid proc.exepath=%proc.exepath user.uid=%user.uid user.loginname=%user.loginname group.gid=%group.gid group.name=%group.name image=%container.image.repository:%container.image.tag) priority: WARNING
最後に、更新したルールをサービスに反映させるために、Falcoのサービスを再起動する必要があります。
sudo service falco restart
Falcoのルールをテストする
それでは、すべてをテストドライブしてみましょう。少なくとも2つのターミナルを使用して、進行中のすべてのことを簡単に追跡できるようにしたいと思います。まず、Falcoのログファイルに起こるあらゆることをフォローするためにtailをセットアップします。おそらく、Falcoのサービスからすでにいくつかのコンテンツがここにあるはずですが、新しいイベントが追加されないか観察したいのです。
ターミナル1にて:
tail -f /var/log/falco_events.log
まず、パラメーターの現在の状態を確認してみましょう。上記の手順をすべて踏んでいれば、dev.cdrom.autocloseはおそらく1に設定されていますが、とにかく覗いてみましょう。
ターミナル2で:
$ sudo sysctl dev.cdrom.autoclose dev.cdrom.autoclose = 1
0になっていれば、それもOKです。その場合は、下のコマンドの意味を逆にすればいいのです。変更してみましょう。
$ sudo sysctl -w dev.cdrom.autoclose=0 dev.cdrom.autoclose = 0
ターミナル 1 の Falco ログの末尾に、カーネルパラメータの変更ルールの出力が表示されるはずです。成功!
11:19:22.673413934: Warning Kernel parameter was modified; possible unauthorized changes (user.name=root user.loginuid=1000 proc.cmdline=sysctl -w dev.cdrom.autoclose=0 parent=sudo file=/proc/sys/dev/cdrom/autoclose container.id=host container_name=host evt.type=openat evt.res=SUCCESS proc.pid=1447007 proc.cwd=/proc/sys/dev/cdrom/ proc.ppid=1447006 proc.pcmdline=sudo sysctl -w dev.cdrom.autoclose=0 proc.sid=5067 proc.exepath=/usr/sbin/sysctl user.uid=0 user.loginname=user group.gid=8390047166231478272 group.name=root image=<NA>:<NA>)
ここで行ったことを拡張するために、sensitive_kernel_parameter_filesのリストに戻って、変更を監視したいパラメータを簡単に追加することができます。リストに追加するためには、パラメータがファイルシステムのどこに存在するかを知る必要があるだけです。
まとめ
カーネルパラメータは一見すると少し怖いですが、どのように構成され、どのように機能するかを少し理解すると、見た目よりも怖くありません。一旦、/proc/sys/ 以下のディレクトリ構造の異なるセクションが何をするのか理解できれば、パラメータを追跡し、その目的を理解することがかなり容易になります。これらのパラメータが何であり、どのようにパラメータを操作することができるかについての知識を得て、システムのセキュリティを強化するためにそれらを使用することに取り組むことができます。カーネルパラメータの変更を監視するためのポイントを理解すれば、予期せぬ変更の影響から自分自身を守ることにもつながります。
Falcoは、特定のコアパラメータの変更について警告し、このプロセスが引き起こす大規模なノイズを回避することができます。
もし、あなたがFalcoについてもっと知りたいのであれば。
- Falco.orgで始める。
- GitHub で Falco プロジェクトをチェックアウトする。
- Falco コミュニティに参加する。
- Falco Slackでメンテナに会う。
- Twitterで@falco_orgをフォローする。