カーネルパラメーターサイドからの物語

By 清水 孝郎 - OCTOBER 31, 2022

SHARE:

本文の内容は、2022年10月31日にJason Andressが投稿したブログ(https://sysdig.com/blog/kernel-parameters-falco/)を元に日本語に翻訳・再構成した内容となっております。

ユーザーは、太陽の光が降り注ぐ世界、それが現実だと自分たちが信じている世界、に住んでいます。しかし、そこには目に見えない裏の世界があります。同じように現実的でありながら、それほど明るく照らされていない場所。それがカーネル・パラメータ側です(ジョージ・ロメロに謝意を表する)。

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 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%向上させることができます。このパラメータがシステム上で不意に変化するのを見ることは、誰かが私たちにマイナーをプレゼントしたことを示す非常に良い指標になるかもしれません。

カーネルパラメータを使って、悪者は何ができるのでしょうか?

一言で言えば、非常に多くのことができます。おそらく、攻撃者はカーネルパラメータを変更するためにシステム上で十分な権限を必要とするか、そうするために他の特権プロセスを転覆させる攻撃をすることになるでしょうが、物事はこれよりもかなり悪くなる可能性があります。

先ほど説明したパラメータの中には、あまり深く掘り下げなくても、ネットワーク攻撃に関連するさまざまな脆弱性を緩和するものがいくつかあります。これらのパラメータの一部または全部を意図的に無効化すると、システムの防御に大きな穴が開く可能性があります。これらは、攻撃者が弄るには本当に醜いパラメータではありません。

Kernel Parameters detection Falco
例として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についてもっと知りたいのであれば。