Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Linux コンテナのリブートとセキュリティ / SosaiLT 38th

tenforward
October 20, 2023

Linux コンテナのリブートとセキュリティ / SosaiLT 38th

総関西サイバーセキュリティLT大会(第38回)の LT 資料です。
参考となる情報にはPDF中からリンクをしていますが、資料中のリンクは Speaker Deck 上ではクリックできないので PDF をダウンロードしてご覧ください。

tenforward

October 20, 2023
Tweet

More Decks by tenforward

Other Decks in Technology

Transcript

  1. 自己紹介   加藤泰文(かとうやすふみ) • X: @ten_forward • LXC で学ぶコンテナ入門 -軽量仮想化環境を実現

    する技術 (gihyo.jp, 2014 年〜) • 趣味でコンテナやってます。コンテナの主にカーネ ル周辺の実装に興味があります • 技術書典でコンテナ技術を紹介する同人本出して います(サークル名: lxc-jp) • コンテナの勉強会を主宰しています • 仕事はセキュリティの部署にいます 2/12
  2. リブートシステムコールを呼ぶコンテナ リブートする機能を持つコンテナを起動する(コンテナ作った瞬間 reboot(2) システムコール実行) 。   static int do_reboot(void

    *arg) { :(略) /* reboot システムコールを呼ぶ */ if (reboot(*cmd)) printf("failed to reboot(%d): %m\n", *cmd); } int test_reboot(int cmd, int sig) { :(略) /* clone(2) でコンテナを作成 */ ret = clone(do_reboot, stack, CLONE_NEWPID | SIGCHLD, &cmd); :(略) } int main(int argc, char *argv[]) { :(略) /* 再起動コマンドを指定してリブート */ status = test_reboot(LINUX_REBOOT_CMD_RESTART, SIGHUP); :(略) /* ホストがリブートするとここにはこない */ printf("reboot(LINUX_REBOOT_CMD_RESTART) succeed\n"); :(略) }   5/12
  3. 古い distro でさきほどのプログラムを実行する(Ubuntu 10.04)   $ virsh console ubuntu10.04

    ドメイン 'ubuntu10.04' に接続しました エスケープ文字は ^] です (Ctrl + ]) Ubuntu 10.04 LTS ubuntu1004 ttyS0 ubuntu1004 login: karma(←コンソールログイン) Password: karma@ubuntu1004:~$ gcc -o reboot reboot.c(←さきほどのプログラムをコンパイル) karma@ubuntu1004:~$ sudo ./reboot(←実行) [sudo] password for karma: [ 34.102303] Restarting system.(←システム再起動!!) fsck from util-linux-ng 2.17.2 fsck from util-linux-ng 2.17.2 /dev/vda1 was not cleanly unmounted, check forced. /dev/mapper/ubuntu1004-root: clean, 50106/482384 files, 259133/1926144 blocks (check after next mount) /dev/vda1: 203/124496 files (2.0% non-contiguous), 32786/248832 blocks mountall: fsck /boot [373] terminated with status 1 * Starting AppArmor profiles [ OK ] Ubuntu 10.04 LTS ubuntu1004 ttyS0 ubuntu1004 login:(←再起動してログインプロンプトが出た)   実演:https://asciinema.org/a/614800 6/12
  4. 少し新しいバージョンで実行する(Ubuntu 12.04) Linux 3.4(2017 年 12 月リリース)以降のカーネルで実行すると(Ubuntu 12.04 はバック ポートされている)

    。   $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 12.04 LTS Release: 12.04 Codename: precise $ sudo ./reboot reboot(LINUX_REBOOT_CMD_RESTART) succeed   コンテナ内で処理が済んでいる。 7/12
  5. 新しいカーネルでは(Linux 3.4 以降) Linux 3.4 で、コンテナ内で reboot(2) を実行したときの処理が追加されました。 どのような処理かというと、reboot(2) システムコールの処理内で、

    1. 自分はコンテナ内にいるかどうか? 2. コンテナ内にいる場合、指定されたコマンドに応じて • 再起動コマンドの場合は SIGHUP を PID 1 のプロセスに発行 • 停止コマンドの場合は SIGINT を PID 1 のプロセスに発行 3. コンテナ内にいない場合、通常の処理を続行 となりました→コンテナ内でリブート・停止しても、コンテナ内のプロセスにシグナルが送 られるだけになりました。 8/12
  6. reboot システムコール内の処理 コンテナ内から reboot(2) システムコールを発行したときの処理が追加されたあとのコー ド(kernel/reboot.c 700 行目(6.1kernel) ) 。

      SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg) { /* 現在の PID Namespace を取得 */ struct pid_namespace *pid_ns = task_active_pid_ns(current); /* reboot() を実行する権限があるかチェック */ if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT)) return -EPERM; :(略) /* PID Namespace 内のリブート処理 */ ret = reboot_pid_ns(pid_ns, cmd); :(略) /* ホストのリブート処理 */ :(略)   (コメントは私が入れています) 9/12
  7. reboot システムコール内の処理(コンテナ内の処理) コンテナ内でのリブート・停止処理(kernel/pid_namespace.c 300 行目(6.1kernel) )   int reboot_pid_ns(struct

    pid_namespace *pid_ns, int cmd) { /* コンテナ内でなければ return */ if (pid_ns == &init_pid_ns) return 0; switch (cmd) { /* リブートの場合は SIGHUP シグナルをセット */ case LINUX_REBOOT_CMD_RESTART2: case LINUX_REBOOT_CMD_RESTART: pid_ns->reboot = SIGHUP; break; /* 停止の場合は SIGINT シグナルをセット */ case LINUX_REBOOT_CMD_POWER_OFF: case LINUX_REBOOT_CMD_HALT: pid_ns->reboot = SIGINT; break; :(略) } /* シグナルの送信 */ send_sig(SIGKILL, pid_ns->child_reaper, 1); :(略) do_exit(0); :(略) }   10/12