再起動せずにカーネルにパッチを適用する方法:livepatch、kpatchおよびCanonical Livepatch Service

pr-3322



再起動せずにカーネルパッチを更新するトピックについては、2014年に公開された記事で既に検討しています。 Cloud Linuxのパートナーが開発したツールであるKernelCareについて説明しました。 この記事の執筆時点では、KernelCareはほぼ唯一の完全に使用可能なパッチツールでした。



2年半が経過し、状況は変化し、劇的に変化しました。バージョン4.0以降、カーネルに正式にパッチを適用する機能が正式に追加されました。



2014年に未加工の状態であったkpatchおよびkGraftツールも大幅に改善されました。 Kpatchは公式リポジトリにも追加されました。たとえば、Ubuntu 16.04では、標準パッケージマネージャーを使用して既にインストールできます。



また、Canonicalは最近、 Canonical Livepatch Serviceを導入しました。これにより、再起動せずにUbuntuコアにパッチを適用できます。



パッチを追加するための最新のツールの詳細については、この記事で説明します。



最も単純な例:livepatch



非常に簡単な実験から始めましょう。 これを行うには、カーネルバージョン4.0以降のLinuxディストリビューションが必要です(この場合はUbuntu 16.04です。以降、コマンドのすべての例はこのディストリビューション専用に提供されています)。 新しいカーネルバージョンでは、パッチをオンザフライで追加する機能(livepatchと呼ばれます)はデフォルトで有効になっています。



動作をテストするには、まずカーネルヘッダーを設定する必要があります。



$ sudo apt-get install linux-headers-$(uname -r)
      
      





次に、カーネルデバッグシンボルをインストールします。



 #  $ codename=$(lsb_release -sc) $ sudo tee /etc/apt/sources.list.d/ddebs.list << EOF deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse deb http://ddebs.ubuntu.com/ ${codename}-security main restricted universe multiverse deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse EOF #  wget -Nq http://ddebs.ubuntu.com/dbgsym-release-key.asc -O- | sudo apt-key add - #   $ sudo apt-get update #   $ sudo apt-get install linux-image-$(uname -r)-dbgsym
      
      





次に、実行します:



 $ sudo apt-get build-dep linux
      
      





Ubuntu 16.04でこのコマンドを実行すると、次のエラーメッセージが表示される場合があります。



 E: You must put some 'source' URIs in your sources.list
      
      





エラーの理由は、deb-srcリポジトリーがデフォルトで接続されておらず、/ etc / apt / sources.listファイル内の対応する行がコメント化されているためです。 ソースコードリポジトリで作業できるように、次のことを行います。



 $ sudo sed -i -- 's/#deb-src/deb-src/g' /etc/apt/sources.list && sudo sed -i -- 's/# deb-src/deb-src/g' /etc/apt/sources.list $ sudo apt-get update
      
      





その後、前のコマンドがエラーなしで実行されます。 実験の準備がすべて整いました。次を開始できます。



 wget http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/samples/livepatch/livepatch-sample.c
      
      





カーネルモジュールコードをダウンロードしました。これにより、コアカーネルコードが変更され、cat / proc / cmdlineコマンドの出力が変更されます。 次に、この同じモジュールを組み立てる必要があります。 これを行うには、次のメイクファイルを作成します。



 obj-m +=livepatch-sample.o KDIR= /lib/modules/$(shell uname -r)/build all: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -rf *.o *.ko *.mod.* .c* .t*
      
      





モジュールをビルドし、カーネルに挿入します。



 $ make $ insmod livepatch-sample.ko
      
      





何が起こったのか見てみましょう。 実行:



 $ cat /proc/cmdinfo
      
      





カーネルパラメータに関する標準情報の代わりに、次のテキストが表示されます。



 this has been live patched
      
      





ご覧のとおり、パッチは正常に適用されました。



ダウンロードしたパッチに関するすべての情報は、/ sys / kernel / livepatchディレクトリに保存されます。



 $ ls /sys/kernel/livepatch/ livepatch_sample
      
      





次のコマンドを使用して、パッチを非アクティブ化できます。



 $ echo 0 > /sys/kernel_livepatch/livepatch_sample/enabled
      
      





パッチ



Kpatchは、Red Hatが開発したツールです。 2016年2月に初めて多くのユーザーに紹介されました 。 この間、大幅に改善されました。Ubuntu16.04では、公式リポジトリにすでに含まれています。 実際の例でkpatchを使用する機能を検討してください。



必要な依存関係をインストールすることから始めましょう。



 $ sudo apt-get install libelf-dev dpkg-dev
      
      





kpatchを完全に使用するには、 ccacheをインストールすることもお勧めします。



 $ sudo apt-get install ccache $ ccache --max-size=5G
      
      





以上で、依存関係がインストールされました。 kpatchをインストールできます。



 $ sudo apt-get install kpatch kpatch-build
      
      





この実験では、カーネルソースにパッチを適用します。 現在のバージョンのUbuntuのソースコードリポジトリを複製します。



 git clone git://kernel.ubuntu.com/ubuntu/ubuntu-xenial.git
      
      





クローン作成が完了したら、ソースをubu​​ntu-xenial-kpatchディレクトリにコピーします(これは、ソースコードを変更し、これらの変更に基づいてパッチを作成するために必要です)。



 $ mkdir ubuntu-xenial-kpatch $ cp -r ubuntu-xenial ubuntu-xenial-kpatch
      
      





ファイルubuntu-xenial-kpatch / ubuntu-xenial / fs / proc / version.cを開き、次の変更を加えます。



 #include <linux/fs.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/utsname.h> static int version_proc_show(struct seq_file *m, void *v) { seq_printf(m, linux_proc_banner, "This has been patched!", utsname()->sysname, utsname()->release, utsname()->version); return 0; }
      
      





次のコマンドを使用してパッチを作成します。



 $ diff -u ubuntu-xenial/fs/proc/version.c ubuntu-xenial.kpatch/ubuntu-xenial/proc.version.c > version.patch
      
      





パッチは、行われた変更をリストするプレーンテキストファイルです。



 --- ubuntu-xenial/fs/proc/version.c 2016-12-05 10:04:30.126141156 +0300 +++ ubuntu-xenial.kpatch/ubuntu-xenial/fs/proc/version.c 2016-12-05 10:10:35.678461801 +0300 @@ -8,6 +8,7 @@ static int version_proc_show(struct seq_file *m, void *v) { seq_printf(m, linux_proc_banner, + "This has been patched!", utsname()->sysname, utsname()->release, utsname()->version);
      
      





カーネルにパッチを追加するには、次を実行します。



 $ kpatch-build -t vmlinux --skip-gcc-check version.patch WARNING: Skipping gcc version matching check (not recommended) Debian/Ubuntu distribution detected Downloading the kernel source for 4.4.0-51-generic Unpacking kernel source Testing patch file checking file fs/proc/version.c Reading special section data Building original kernel Building patched kernel Detecting changed objects Rebuilding changed objects Extracting new and modified ELF sections version.o: changed function: version_proc_show Building patch module: kpatch-version.ko SUCCESS
      
      





上記の出力からわかるように、出力でカーネルモジュールを取得します。 パッチを適用するには、このモジュールを標準的な方法で追加するだけです。



 sudo insmod kpatch-version.ko
      
      





結果として何が起こったのか見てみましょう:



 cat /proc/version This has been patched! version Linux (buildd@lcy01-08) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) ) 4.4.0-51-generic
      
      





すべてが機能します!



Canonical Livepatch Service



数か月前、Canonicalは公式のCanonical LivePatch Serviceを開始しました。これにより、最も簡単なコマンドを使用してカーネルを「オンザフライ」でパッチできます。 このサービスは主に企業レベルのユーザーを対象としているため、有料です。



ただし、一般ユーザーも最新のカーネルアップデートをすぐに受け取ることができます。 これを行うには、Ubuntu Oneに登録してトークン取得する必要があります 。 このトークンにより、3台のマシンにcanonical-livepatchプログラムをインストールし、パッチをダウンロードして追加できます。



Canonical Livepatch Serviceの仕組みを見てみましょう。 上記のリンクをたどり、トークンを取得してから実行します。



 $ sudo snap install canonical-livepatch
      
      





インストールが完了したら、システムからログアウトし、再度ログインして実行します。



 $ sudo canonical-livepatch enable []
      
      





すべてが正しく行われた場合、次のメッセージが表示されます。



 Successfully enabled device. Using machine-token: []
      
      





次に、コマンドを実行します。



 $ canonical-livepatch status kernel: 4.4.0-47.68-generic fully-patched: true version: "14.1"
      
      





出力は、canonical-livepatchが機能し、最新の更新がすべてカーネルにインストールされていることを示しています。 詳細については、-verboseオプションを使用してください。



 $ canonical-livepatch status --verbose client-version: "6" machine-id: [id] machine-token:[token] architecture: x86_64 cpu-model: Intel(R) Xeon(R) CPU E5-2670 v3 @ 2.30GHz last-check: 2016-12-05T11:56:02.88803394+03:00 boot-time: 2016-11-29T10:48:38+03:00 uptime: 145h18m21s status: - kernel: 4.4.0-47.68-generic running: true livepatch: checkState: checked patchState: applied version: "14.1" fixes: |- * CVE-2016-7425 * CVE-2016-8658
      
      





また、上記の/ sys / kernel / livepatchディレクトリを見ると、インストールされているパッチに関する情報を取得できます。



 $ ls /sys/kernel/livepatch kpatch_livepatch_Ubuntu_4_4_0_47_68_generic_14
      
      





Kpatch_livepatch_Ubuntu_4_4_0_47_68_generic_14-これは最後にダウンロードされたパッチです。 パッチ名の最後の数字(14)は、canonical-livepatch statusコマンドの出力に示されているバージョン番号と一致します(上記を参照)。



lsmodコマンドを使用して、新しいパッチが追加されたことを確認することもできます。



 $ lsmod |grep livepatch kpatch_livepatch_Ubuntu_4_4_0_47_68_generic_14 36864 1
      
      





おわりに



この記事では、Linuxカーネルにパッチを追加するためのツールを少し選択しました。 当然、単一の出版物の中でトピックのすべての側面に触れることは不可能です。 コメントや追加がある場合-コメントへようこそ。



また、トピックをより深く学習したい場合は、次のリンクに注意してください。





何らかの理由でここにコメントを残せない場合は、 当社の企業ブログへようこそ。



All Articles