CVE-2018-14634(Integer overflow in Linux's create_elf_tables function)でRed Hatのbugzillaを見ていて軽減策としてsystemtapでlivepatch的なことをしていて面白いな〜って思ったのでめもです。
環境はFedora 28で、カーネルのバージョンは4.18.9-200です。systemtapを使っているのでkernel-debuginfoパッケージも入れてます。
utsname構造体のnodenameを書き換えてホスト名を変えてみたいと思います。まずは初期状態はこうです。kerntestがnodenameになります。
masami@kerntest:~$ uname -a Linux kerntest 4.18.9-200.fc28.x86_64 #1 SMP Thu Sep 20 02:43:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
cのコードでuname(2)を実行するものを作ります。
#include <stdio.h> #include <sys/utsname.h> int main(int argc, char **argv) { struct utsname utsname = { 0 }; printf("call uname(2) to execute livepatch via systemtap\n"); if (uname(&utsname)) { perror("uname"); return -1; } printf("patched nodename: %s\n", utsname.nodename); return 0; }
まずはこれを-oオプション無しにコンパイルしてa.outで実行した場合。
masami@kerntest:~$ ./a.out call uname(2) to execute livepatch via systemtap patched nodename: kerntest
なにも起きませんね。
次に以下のsystemtapのスクリプトを実行します。 uname(2)で呼ばれる__do_sys_newuname()にprobeを設定しています。 このスクリプトの内容としてはuname(2)を実行したプロセス名がdo-livepatchならそのプロセスが所属するuts名前空間に設定されてるnodenameの値を書き換えてます。
#!/usr/bin/env stap %{ #include <linux/sched.h> #include <linux/string.h> %} function set_dummy_uname:long() %{ struct task_struct *p = current; if (strcmp(p->nsproxy->uts_ns->name.nodename, "livepatched")) { if (unlikely(!strcmp(p->comm, "do-livepatch"))) { memset(p->nsproxy->uts_ns->name.nodename, 0, sizeof(p->nsproxy->uts_ns->name.nodename)); strcpy(p->nsproxy->uts_ns->name.nodename, "livepatched"); } } STAP_RETURN(0); %} probe begin { printf("start\n") } probe kernel.function("__do_sys_newuname") { set_dummy_uname() } probe end { printf("Done\n") }
上記のコードを実行します。
masami@kerntest:~$ sudo stap -v -g test.stp Pass 1: parsed user script and 474 library scripts using 157272virt/50300res/8740shr/41432data kb, in 90usr/20sys/106real ms. Pass 2: analyzed script: 3 probes, 1 function, 1 embed, 0 globals using 211816virt/105600res/9628shr/95976data kb, in 750usr/30sys/777real ms. Pass 3: translated to C into "/tmp/stapmurOiN/stap_134d2448e08da1a0409648297476fac2_1549_src.c" using 211816virt/105912res/9940shr/95976data kb, in 10usr/0sys/6real ms. Pass 4: compiled C into "stap_134d2448e08da1a0409648297476fac2_1549.ko" in 1990usr/740sys/2506real ms. Pass 5: starting run. start
そして、cコードの方をdo-livepatchという名前のバイナリでコンパイルして実行するとnodenameが書き換えられます。これ以降はuname(2)は変更した名前が返るようになってます。
masami@kerntest:~$ ./do-livepatch call uname(2) to execute livepatch via systemtap patched nodename: livepatched masami@kerntest:~$ uname -a Linux livepatched 4.18.9-200.fc28.x86_64 #1 SMP Thu Sep 20 02:43:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux masami@kerntest:~$ uname -n livepatched
今まではすでにログインしてたのでbashプロンプトのほうはホスト名変わってませんが、新規に接続するとホスト名が新しい名前になってます。
masami@saga:~$ ssh kerntest Last login: Thu Sep 27 02:05:41 2018 from 192.168.122.1 masami@livepatched:~$
というわけで、systemtapでlivepatch的なことをする実験でした( ´ー`)フゥー...
ふつうのLinuxプログラミング 第2版 Linuxの仕組みから学べるgccプログラミングの王道
- 作者: 青木峰郎
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2017/09/22
- メディア: 単行本
- この商品を含むブログを見る