Hatena::ブログ(Diary)

へにゃぺんて@日々勉強のまとめ

2017-12-17

Debian Jessie以前で最近のLinuxカーネルをmake-kpkgする際に"missing REPORTING-BUGS"に陥った際の対処

本記事はDebian/Ubuntu Advent Calendar 2017の12/17(日)向けに書いてみた小ネタです。


Debian Jessieを今だに抜け出せず、使い続けているのもアレなのですが、Jessieでmake-kpkgで最近のLinuxカーネルビルドしようとすると"missing REPORTING-BUGS"というエラーに陥るので、その対処方法について記事にしてみます。

はじめに

なお、先に書いておくと、Stretchからはmake-kpkgは入っていません。Linuxカーネルdebパッケージへのビルドは、MainlineのMakefileにも"deb-pkg"や"bindeb-pkg"といったターゲットが入っており、make-kpkgは必要なくなっています。


最近の方法でLinuxカーネルdebパッケージ作成方法については、Debian公式のドキュメントに日本語で情報があります。


本題

さて、表題の問題については、結論を書くと「Documentationの"REPORTING-BUGS"ファイルが"admin-guide/reporting-bugs.rst"へ変わった」というだけです。そのため、/usr/share/kernel-package/ruleset/targets/headers.mkでエラーが起きている、というものです。


headers.mkを以下のように修正すれば解消できます。

/usr/share/kernel-package/ruleset/targets$ diff -u headers.mk.old headers.mk
--- headers.mk.old    2017-03-04 02:50:04.024045713 +0100
+++ headers.mk    2017-03-04 03:35:42.656057547 +0100
@@ -67,7 +67,10 @@
	   $(install_file) debian/stamp/conf/vars      $(DOCDIR)/conf.vars
     $(install_file) CREDITS                         $(DOCDIR)/
     $(install_file) MAINTAINERS                     $(DOCDIR)/
+    test ! -f REPORTING-BUGS            || \
     $(install_file) REPORTING-BUGS                  $(DOCDIR)/
+    test ! -f Documentation/admin-guide/reporting-bugs.rst    || \
+    $(install_file) Documentation/admin-guide/reporting-bugs.rst
$(DOCDIR)/
     $(install_file) README                          $(DOCDIR)/
     if test -f README.Debian ;
then                                                 \
	    $(install_file) README.Debian
$(DOCDIR)/README.Debian.1st;\

なお、この問題はbugs.debian.orgでも報告されており、上記パッチは報告内容の受け売りです。


さいごに

冒頭にも書いたとおり、make-kpkgはもはや使わないほうが良いのですが、make-kpkgで自動ビルドするスクリプトとか作っているとなかなか抜け出せないため、そんな方の参考になれば幸いです。

2017-12-10

QEMU/実機共に起動できるDebianをUSBフラッシュメモリに構築する

本記事は少し早いですがDebian/Ubuntu Advent Calendar 2017の12/12(火)向けに書いた記事です。Debian関係で最近やったことを記事にしてみます。


Linuxカーネルのブロックレイヤー向けドライバを動かしてみる時などに、Linuxカーネルごと別の環境が欲しくなります。複数台PCを持っていなかったりすると、仮想マシンとして立ち上げることを考えますが、実行速度を求めたい時など、仮想環境を直接PC上で実行したい時もあります。


本記事ではQEMU上でも実機上でも起動できるDebian環境をUSBフラッシュメモリへ構築する方法を紹介します。


といっても、結論から書くと単にQEMUを使用してUSBフラッシュメモリインストールするだけです。ただし、UEFI向けにインストールする場合、少し変更が必要な箇所があります。


この記事ではQEMUを使用してUSBフラッシュメモリDebian環境を構築する方法を紹介します。当然、Debianインストールディスクを直接実機で起動してインストールを行った方がインストールにかかる時間は短くて済むのですが、インストールしている最中に同じPCで別の作業を行えるのは便利です。


レガシーBIOS向け

$ sudo qemu-system-x86_64 -m 1024 -cdrom debian-9.2.1-amd64-netinst.iso -hda /dev/sdb

USBフラッシュメモリは /dev/sdb で認識されているとします

インストールディスクは"debian-9.2.1-amd64-netinst.iso"というファイル名でダウンロードしてあるとします。

QEMUへ割り当てるメモリは1GBとしていますが(-mオプション)、搭載されているメモリに合わせて適宜変更してください


インストール完了後、実機で起動する際はBIOS設定を変更し、インストールしたUSBフラッシュメモリから起動してください。


また、QEMU上で起動する際は以下のコマンドを実行します。

$ sudo qemu-system-x86_64 -m 1024 -hda /dev/sdb

UEFI向け

QEMUにはUEFI対応のファームウェアは含まれていないため、OVMF(Open Virtual Machine Firmware)パッケージをインストールします。

$ sudo apt install ovmf

その後、以下のコマンドでUSBフラッシュメモリインストールを行います。

$ sudo qemu-system-x86_64 -bios OVMF.fd -m 1024 -cdrom debian-9.2.1-amd64-netinst.iso -hda /dev/sdb

レガシーBIOS向けのコマンドラインへ"-bios OVMF.fd"オプションを追加しただけです


インストール完了後、QEMUからはそのまま以下のコマンドで起動できます。

$ sudo qemu-system-x86_64 -bios OVMF.fd -m 1024 -hda /dev/sdb

しかし、実機では起動できないと思われます。(少なくとも私のPC(Lenovo Thinkpad)では起動不可)


レガシーBIOSの場合、PC起動時にBIOSは起動ディスクの先頭512バイト(MBR)を見に行きます。対してBIOSUEFI準拠の場合、UEFIFATファイルシステムを認識できるのでPC起動時に起動ディスクの第1パーティションに決まったファイル名でOS起動用のファイル(主にブートローダー)が置かれているかを見に行きます。


DebianUEFI向けにインストールした時、第1パーティションには"efi/debian/grubx64.efi"というパスでブートローダー(GRUB)がインストールされますが、UEFIファームウェアによってはこのパスでこのファイルを見つけられなかったりします。UEFIの仕様としては"EFI/BOOT/BOOTx64.EFI"(FATなので大文字小文字区別無し)というパスを探しに行きます[*1]。

[*1] http://www.uefi.org/specifications


そのため、DebianインストールしたUSBフラッシュメモリ第1パーティションの"efi/debian/grubx64.efi"を"efi/boot/bootx64.efi"へコピーしておけば、実機から起動できるようになります。

$ sudo mount /dev/sdb1 /mnt
$ sudo mkdir -p /mnt/efi/boot
$ sudo cp /mnt/efi/debian/grubx64.efi /mnt/efi/boot/bootx64.efi
$ sudo umount /mnt

2017-12-05

QEMU上で'_'(アンダーバー)を入力できない問題の解決法(debian packageへのコード修正・再ビルド)

少し早いですが、本記事はDebian/Ubuntu Advent Calendar 2017の12/7(木)の記事として書いてみたものです。


qemu-system-x86_64(qemu-system-x86パッケージ、バージョン:1:2.1+dfsg-12+deb8u6)を使用していて、ゲスト上で'_'(アンダーバー)を入力できないという問題がありました。


ソースコードの修正が必要で、以下の記事等で修正方法が紹介されています。


Debianパッケージのソースコードを取得して、ソースコード修正し、debパッケージ再生成を行ってみましたので、

この記事ではその手順をまとめておきます。


手順1. パッケージのビルドに必要なパッケージをインストール

$ sudo apt-get build-dep qemu-system-x86

手順2. qemu-system-x86パッケージのソースコードを取得

$ apt-get source qemu-system-x86

ソースコードダウンロードにより"qemu-2.1+dfsg"というディレクトリが作られているとします。


手順3. ソースコード修正

qemu-2.1+dfsg/ui/x_keymap.c を以下のように修正

--- a/ui/x_keymap.c     2013-08-09 07:40:09.530318381 +0900
+++ b/ui/x_keymap.c     2013-08-09 07:38:27.310309931 +0900
@@ -94,7 +94,7 @@
  */

 static const uint8_t evdev_keycode_to_pc_keycode[61] = {
-    0,         /*  97 EVDEV - RO   ("Internet" Keyboards) */
+    0x73,      /*  97 EVDEV - RO   ("Internet" Keyboards) */
     0,         /*  98 EVDEV - KATA (Katakana) */
     0,         /*  99 EVDEV - HIRA (Hiragana) */
     0x79,      /* 100 EVDEV - HENK (Henkan) */

手順4. debパッケージ再生成

$ cd qemu-2.1+dfsg
$ dpkg-buildpackage -rfakeroot -uc -b

2016-12-15

chrootとunshareを使い、シェル上でコマンド7つで簡易コンテナ

コンテナ型仮想化であるDockerは、様々な名前空間の分離やcgroupなどのLinuxの機能を使用して実現されています。


ここでは、簡易的に機能を「ルートディレクトリとPID名前空間も分離されている」と限定し、シェル上で7つのコマンドでコンテナを立ち上げてみます。


最終的な目標は、立ち上げたコンテナ上でpsを実行し、以下のようにPIDが1から割り振られていることを確認することです。

bash-4.3# ps
  PID TTY          TIME CMD
    1 pts/1    00:00:00 bash
    7 pts/1    00:00:00 ps
bash-4.3#

結論: 7つのコマンド

先に書いてしまうと、7つのコマンドは以下のとおりです。


まず、簡易コンテナの作成から、コンテナ内のbash起動まで。

$ mkdir test_container
$ cd test_container
$ cp -r /bin /lib /lib64 .
$ sudo unshare -pf chroot . bash

新たにbashが立ち上がりますので、

psを実行するためにprocとdevptsのマウント。

mkdir -p /proc /dev/pts
mount -t proc proc /proc
mount -t devpts devpts /dev/pts

以上で準備完了です。


psを実行してみると、PIDが新たに1から割り振られていることを確認できます。

bash-4.3# ps
  PID TTY          TIME CMD
    1 pts/1    00:00:00 bash
    5 pts/1    00:00:00 ps

また、"ls /"を試すと、"test_container"ディレクトリ内で作成したものしか無く、

ルートディレクトリを"test_container"へ変更できていることを確認できます。

bash-4.3# ls /
bin  dev  lib  lib64  proc

説明: chrootコマンドとunshareコマンド

今回重要となるコマンドは、4つ目で実行したchrootコマンドとunshareコマンドです。


chrootコマンドは、ルートディレクトリを変更するコマンドで、以下のように使用します。

# chroot 新たにルートとするディレクトリ ルートディレクトリ変更後に実行するコマンド

chrootを実行すると、第1引数のディレクトリを新たなルートディレクトリ(/)として、第2引数のコマンドを実行します。

なお、ルートディレクトリを変えたあと第2引数のコマンドを実行するので、第2引数のコマンドの実行バイナリ自体と、実行バイナリが参照する共有ライブラリは、第1引数のディレクトリ内に存在する必要があります。(そのため、3つ目のコマンドで/binと/lib・/lib64をコンテナ内へコピーしていました。)


また、unshareコマンドは、様々な名前空間の分離を行うコマンドで、以下のように使用します。

# unshare [オプション] コマンド [コマンドの引数]

オプションでは「何の名前空間を分離するか」を指定します。

今回は、以下の2つのオプションを使用しました。

pPID名前空間の分離
f指定したプログラムを直接実行するのではなくunshareの子プロセスとしてfork

なお、chrootとunshare共に、同名のシステムコールが存在し、コマンドはシステムコールをシェル上から呼び出すものとなっています。


参考

今回の記事はunshareとchrootの紹介のような記事ですが、

もっとしっかりと、シェルスクリプトでコンテナ型仮想化を実現しているものとして、

MINCS」があります。


製作者の方の解説記事も勉強になります。

2016-07-24

out of treeでライブパッチを試す、/dev/nullへのパッチ紹介

Linuxカーネルのバージョン4.0から追加されたライブパッチ(Livepatch)機能を今更ながら、試してみました。

(Linux4.0の記事でライブパッチに触れていますが、32bitのマシンしか無く、試せなかったんですね。。)


なお、本記事は「CLR/H #clrh101」のLTで発表させていただいた内容のまとめです。


この記事で行うこと

「ライブパッチとは何ぞや」はLinux4.0の記事で触れているので省略し、さっそく使ってみます。


Linuxカーネルソースコードに付属するサンプルをカーネルコンフィグで有効化し、

カーネルビルド時にビルドする」方法は、色々な記事で紹介されているので、

ここでは、

1. カーネルソースツリーの外(out of tree)で、ライブパッチのソースコード単体でビルド

2. 現在動作中のカーネルに再起動無しで、パッチを適用

を試してみます。

(といっても、単なるカーネルモジュールなので、

一般的な「out of treeでのビルド」と「insmod」という話です。)


0. Linuxカーネルビルドインストール・起動

ライブパッチに限らず、カーネルモジュールのビルド時、ビルド済のカーネルソースツリーを参照するので、

Linuxカーネルビルドを行います。


また、カーネルモジュールはビルドしたカーネルと対応するので、

ビルドしたカーネルインストール後、再起動します。


なお、前述の通りライブパッチLinuxカーネルのバージョン4.0で追加された機能です。

Debian 8(Jessie)時点でLinuxカーネルのバージョンは3.16なので、

(少なくともDebianにおいて、Debianをお使いであれば、)

Linuxカーネルソースは本家であるThe Linux Kernel Archivesのものを使用すると良いです。


カーネルコンフィギュレーションやビルドインストールについては、Linux4.0の記事を参考にしてください。


1. ライブパッチビルド

ライブパッチのサンプルをout of treeビルドしてみます。


まず、作業ディレクトリ(livepatch-sample)を作成し、サンプルソースコードをコピー

[PC ~]$ mkdir livepatch-sample
[PC ~]$ cp linux-4.6.4/samples/livepatch/livepatch-sample.c livepatch-sample/

次に、以下の内容をMakefileというファイル名でlivepatch-sampleディレクトリに保存します。

obj-m = livepatch-sample.o

all:
	make -C $(KERNEL_SRC) M=$(PWD)

clean:
	make -C $(KERNEL_SRC) M=$(PWD) clean

livepatch-sampleへ移動し、以下のコマンドでビルドできます。

ビルドが完了すると"livepatch-sample.ko"というファイルができあがっています。

[PC ~]$ cd livepatch-sample
[PC ~/livepatch-sample]$ make KERNEL_SRC=../linux-4.6.4
・・・ビルドログ・・・
[PC ~/livepatch-sample]$ ls livepatch-sample.ko
livepatch-sample.ko

2. パッチの適用

これをinsmodでインストールすると、パッチを適用できます。

このパッチは、カーネルが生成している/proc/cmdlineの内容を変更するパッチなので、

パッチ適用前後に内容を確認します。

[PC ~/livepatch-sample]$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-4.6.4 root=UUID=e53154c7-c353-49e6-8ba7-9976df1e9ff9 ro quiet
[PC ~/livepatch-sample]$ sudo insmod livepatch-sample.ko
[PC ~/livepatch-sample]$ cat /proc/cmdline
this has been live patched

なお、/var/log/messagesを確認すると、insmod時に以下のログが出ています。

Jul 24 17:13:20 seven kernel: [ 275.460680] livepatch: tainting kernel with TAINT_LIVEPATCH

Jul 24 17:13:20 seven kernel: [ 275.460683] livepatch: enabling patch 'livepatch_sample'

"taint"は「汚れる」といった意味で、「ライブパッチによりカーネルを汚した」といったことを意味しています。

ライブパッチ機能によりソースコードが公開されていないバイナリをカーネルに適用する可能性もあるので、

バグレポートなどの際に、カーネル開発者がログから「汚されていないか」を確認する意味があります。


補足: /dev/null へのパッチ

CLR/H #clrh101」のLTの最後に紹介した

「/dev/nullをreadするとメッセージを出力する」パッチはGitHubの以下の場所にpushしました。

使い方などは、上記URL先のREADMEをご覧ください。