2011年9月22日木曜日

UEFI secure booting

Since there are probably going to be some questions about this in the near
future:

The UEFI secure boot protocol is part of recent UEFI specification releases.
It permits one or more signing keys to be installed into a system firmware.
Once enabled, secure boot prevents executables or drivers from being loaded
unless they're signed by one of these keys. Another set of keys (Pkek)
permits communication between an OS and the firmware. An OS with a Pkek
matching that installed in the firmware may add additional keys to the
whitelist. Alternatively, it may add keys to a blacklist. Binaries signed
with a blacklisted key will not load.

There is no centralised signing authority for these UEFI keys. If a vendor
key is installed on a machine, the only way to get code signed with that key
is to get the vendor to perform the signing. A machine may have several keys
installed, but if you are unable to get any of them to sign your binary then
it won't be installable.

This impacts both software and hardware vendors. An OS vendor cannot boot
their software on a system unless it's signed with a key that's included in
the system firmware. A hardware vendor cannot run their hardware inside the
EFI environment unless their drivers are signed with a key that's included
in the system firmware. If you install a new graphics card that either has
unsigned drivers, or drivers that are signed with a key that's not in your
system firmware, you'll get no graphics support in the firmware.

Microsoft requires that machines conforming to the Windows 8 logo program
and running a client version of Windows 8 ship with secure boot enabled. The
two alternatives here are for Windows to be signed with a Microsoft key and
for the public part of that key to be included with all systems, or
alternatively for each OEM to include their own key and sign the
pre-installed versions of Windows. The second approach would make it
impossible to run boxed copies of Windows on Windows logo hardware, and also
impossible to install new versions of Windows unless your OEM provided a new
signed copy. The former seems more likely.

A system that ships with only OEM and Microsoft keys will not boot a generic
copy of Linux.

Now, obviously, we could provide signed versions of Linux. This poses
several problems. Firstly, we'd need a non-GPL bootloader. Grub 2 is
released under the GPLv3, which explicitly requires that we provide the
signing keys. Grub is under GPLv2 which lacks the explicit requirement for
keys, but it could be argued that the requirement for the scripts used to
control compilation includes that. It's a grey area, and exploiting it would
be a pretty good show of bad faith. Secondly, in the near future the design
of the kernel will mean that the kernel itself is part of the bootloader.
This means that kernels will also have to be signed. Making it impossible
for users or developers to build their own kernels is not practical.
Finally, if we self-sign, it's still necessary to get our keys included by
ever OEM.

There's no indication that Microsoft will prevent vendors from providing
firmware support for disabling this feature and running unsigned code.
However, experience indicates that many firmware vendors and OEMs are
interested in providing only the minimum of firmware functionality required
for their market. It's almost certainly the case that some systems will ship
with the option of disabling this. Equally, it's almost certainly the case
that some systems won't.

It's probably not worth panicking yet. But it is worth being concerned.

Next-gen boot spec could forever lock Linux off Windows 8 PCs

Windows 8 PCs will boot super fast in part because of the next-generation booting specification known as Unified Extensible Firmware Interface (UEFI). The latest UEFI, released April 8, includes a secure boot protocol which will be required for Windows 8 clients. Secure UEFI is intended to thwart rootkit infections by requiring keys before allowing executables or drivers to be loaded onto the device.Problem is, such keys can also be used to keep the PC's owner from wiping out the current OS and installing another option such as Linux, says Matthew Garrett, a mobile Linux developer at Red Hat, in a blog post.

'If a vendor key is installed on a machine, the only way to get code signed with that key is to get the vendor to perform the signing. A machine may have several keys installed, but if you are unable to get any of them to sign your binary then it won't be installable. ... Microsoft requires that machines conforming to the Windows 8 logo program and running a client version of Windows 8 ship with secure boot enabled.'

Microsoft's requirement of secure UEFI is verified by a presentation at the BUILD conference given by Arie van der Hoeven, Principal Lead Program Manager of Microsoft. Slide 11 of the presentation states:

  • Current issues with boot
    • Growing class of malware targets the boot path
    • Often the only fix is to reinstall the operating system
  • UEFI and secure boot harden the boot process
    • All firmware and software in the boot process must be signed by a trusted Certificate Authority (CA)
    • Required for Windows 8 client [emphasis mine]
    • Does not require a Trusted Platform Module (TPM)
    • Reduces the likelihood of bootkits, rootkits and ransomware

Secure boot uses a PKI scheme so that UEFI 2.3.1 firmware will only run digitally signed EFI bootloaders and device drivers. A recent article in The H notes that it can be "designed to accept a software key management service (KMS), a network-accessible key server or a hardware security module (HSM)." The hardware module would likely be a Trusted Platform Module (TPM 1.2), though as van der Hoeven points out, TPM isn't required.

The Linux community has been on alert about secure UEFI for a couple of months, according to an article in June from LWN.net:

'The basic idea behind secure boot is to sign executables using a public-key cryptography scheme (RSA with 2048-bit keys with SHA-1 or SHA-256 as the hash). The public part of a 'platform key' (PK) can be stored in the firmware for use as a root key. Additional 'key exchange keys' (KEKs) can also have their public portion stored in the firmware in what is called the 'signature database'. That database contains public keys that can be used to verify different components that might be used by UEFI (e.g. drivers) as well as bootloaders, and operating systems that get loaded from external sources (disks, USB devices, network, and so on). The signature database will also contain 'forbidden' signatures which correspond to a revocation list of previously valid keys. The signature database is meant to contain the current list of authorized and forbidden keys as determined by the UEFI organization.'

The fear expressed by the Linux community in June was that proprietary operating system vendors could demand an implementation of Secure UEFI where device makers do not or cannot share private keys with the buyers/users of the device. Without that, only the entities in the signature database will be able to authenticate drivers and OSes for the hardware.

There are two ways Microsoft could go with its required secure UEFI, says Garrett. Windows can be signed with a Microsoft key and the public part of that key can be included with all systems. Or, each OEM could have its own private key and therefore be the one to sign its own pre-installed version of Windows.

Without a key, Linux will be unable to boot off the machine. It may be possible for Linux distro makers to somehow offer signed versions of Linux, but this too, is problematic as this would require a bootloader not covered by the GPL. It also doesn't help people who want to run their own custom-tweaked versions of Linux.

Enterprise users should be sure to voice their concerns with their hardware supplier (Dell, IBM, HP, Toshiba and so on). Let them know that just because the technology exists to take choice away from you, doesn't mean they should use it.

2011年9月20日火曜日

デバッガベンダーが語る「Android」とは?

 

AndroidはLinuxとは違う」——。組み込み開発分野におけるデバッグ環境を提供する京都マイクロコンピュータが開発者向けにセミナーを開催(2011年8月)し、Androidの開発を行う上でのヒントとなる情報を披露した。AndroidはLinuxをベースとしたソフトウェアプラットフォームだが、実際、Linuxとは大きく異なる特徴を持つ。そのため、LinuxやAndroidの採用を検討する場合、その違いを正しく把握・理解することが重要となる。

 そもそもAndroidはLinuxをベースにしているが、「Linuxカーネルしか使っていない」と小林氏。AndroidアプリはJavaで作られており、Java SEと似ているが、これも同等ではない。AndroidはJavaを実行環境のDalvik VM(Virtual Machine:仮想マシン)上で実行するが、これ自体も「オラクル(のJava)とは随分違っており、コードをそのまま実行するのではなく、"Dalvik Executable(DEX)"と呼ばれる独自形式のコードに変換し、Dalvik VM上で動作させている」。

 Dalvik VMは、Javaのバイトコードから変換したDEX形式のコードを実行するVMで、Java VMの"スタックベース"と比べ、16ビット単位の"レジスタベース"になっているのが特徴だ。実行速度を向上させるために使われるJIT(Just in Time)は、Androidでも2.2から搭載されるようになり、高速化が図られている。また、Androidではガベージコレクション(Garbage Collection:GC)機能も搭載されているが、これは実行中にアプリ動作が停止する瞬間があって不評だったという。これに対して、Android 2.3からは「コンカレントGC」と呼ばれる技術が投入され、この停止時間が短縮化されているそうだ。

 Androidのシステム構成は、一番下層にLinuxカーネルがあり、その上に各種ライブラリとAndroidランタイムが存在する。「Android以前のJava搭載携帯電話では、それまで使っていたOSの上に、後からJava VMを載せたため、メールソフトやブラウザはJavaとは関係なく、そこにさらにJavaが混在していた」と説明。そのため、システムの中身は非常に複雑だったという。これに対して、Androidではシステムの根幹からJavaを動かす構成になっているため、「Javaは"一級市民"という扱いになった」と小林氏は表現する。

 Dalvik VMは、Androidランタイムの中心にあり、ほとんどのDaemonもJavaで記述され、Androidアプリの起動から入力待ち、終了などといったライフサイクルはJava APIで規定されている。

 さらに、AndroidではNDK(Native Development Kit)が用意されており、JNI(Java Native Interface)を利用してC/C++やOpenGL ESといったネイティブコードを実行できるようになっている。「Javaでアプリを書くとき、ゲームなどで性能を上げるためにC++のアプリをリンクさせるような開発ツール」(同)であり、ネイティブライブラリを呼び出すことで実現しているが、アプリのライフサイクル自体は変更がない。NDKでは、新たにネイティブアクティビティが用意され、C/C++の既存のプログラムが移植しやすくなったことで、「Javaの部分を書かなくてもアプリが作れるようになった」(同)点がポイントだ。

 Androidのディレクトリツリーは、通常のLinuxとは異なっている。一般的なLinuxはHDDにファイルシステムが存在する前提で、全てのディレクトリでリード/ライトが可能になっている。しかし、Androidはフラッシュメモリを利用し、リードオンリーでマウントされているルートシステムが存在し、書き換えができないようになっている。つまり「組み込みシステムを意識した構造になっているといえる」わけだ。そのため、例えばシステムアップデートをする場合は、丸ごと置き換わることになる。また、システム実行中は書き換えができないので、バグやマルウェアでもシステムの変更はできない。

 次に、Androidのブートシーケンスを見てみると、カーネルからinitプロセスが起動し、そこからDaemonやサービスマネジャー、Zygoteなどが起動している。ZygoteからはDalvik VMなどが起動される。

 ここで登場するinitは、「通常のLinuxと名前は一緒だが、内容は違う」。カーネルから起動しているが、「ルートディレクトリ直下は検索パスに入っていない」(同)ため、initの位置を指定しないとプログラムが動作しなくなってしまう。Linuxとは異なり、スタティックリンクを設定する必要があり、「FreeBSD系統だと大事なプロセスはスタティックリンクされている」のと同等といえる。

 標準のライブラリであるBionicは、「BSD系のものを寄せ集めた」(同)libcやlibmなどが用意されている。WebKitのようにC++で書かれたている部分もあるが、libcは「小さなシステム向けで、C++の型情報などはサポートしていない」(同)という。また、例外は使われないようになっており、こうしたアプリを移植する際はNDKを使うことで解決する仕組みが用意されている。C++のライブラリをスタティックリンクするようにしており、アプリのサイズは大きくなってしまうものの、例外処理が利用できるようになるそうだ。

 prelinkでは、あらかじめAndroidのライブラリに振られたアドレスに対してリンクが設定され、アドレス解決を簡素化している。小さな組み込みシステム向けに作られたシステムで、全ライブラリに固定したアドレスが割り振られ、3Gバイトのユーザー空間に全ライブラリを並べることが可能。普通、UNIXのシステムではライブラリを固定せず、ライブラリが変わるとサイズが変わってしまい、それを解決する必要がある。Androidはシステムの書き換えができないため、簡単にダイナミックリンクが実現できるのがメリットだ。

 Androidでは、独立した各JavaのプロセスでDalvik VMが起動しているため、Javaアプリの数だけDalvik VMが動作している。この場合に一つずつDalvik VMを起動していると時間がかかるので、「ひな型が用意されている」。それが"接合子"を意味するZygoteで、システムフォークで丸ごとコピーを作ることによって、実メモリ空間上は共有しながら、仮想メモリを使って高速化を図っている。メモリへの書き込みがあったところだけをコピーし、書き込みが行われない部分は共有したままにする「Linuxの仮想メモリを使ったうまい方法」を用いている。

 Zygoteでは、あらかじめ1800個ほどのクラスをロードしておき、それをプロセスの元にすることで、「フォークした瞬間に子プロセスが動く」状態になる。ダイナミックリンクライブラリもメモリにロードされた状態で、フォークした瞬間に子プロセスが動作する形だ。プロセスの生成では通常、forkとexecを使うが、execでは「まっさらになってしまう」(同)ために使われず、「普通は前のプロセスの残骸を有効活用する」という考え方に基づいているとのこと。

 また、LinuxはもともとマルチユーザーのOSで、複数の人が1つのコンピュータを共同で使う前提であり、他人のファイルなどが見えては問題があるので、それを区別する仕組みとして「UID」「GID」といったものが用意されている。この仕組みを流用したのがAndroidだ。

 Androidではアプリを任意にダウンロードして利用できるが、アプリ間で相互に読み書きできてしまっては問題がある。それをOSが区別するためにUIDが使われている。「Androidは全てのアプリが個別のUIDを持っていて、その権限でファイルが作成され、他のアプリからそのファイルは読み書きできない」(同)。ちなみに、ZygoteはUIDが0(root)で動作する。

 Androidで使われるJavaのライブラリは、従来の携帯電話で利用されていたJava MEと比べるとJava SEに近いが、それでも同等ではないという。特に、画面表示周りでAWT(Abstract Window Toolkit)やSwingがなく、Android特有のグラフィックライブラリを使っている。他にRMI(Remote Method Invocation)も搭載されておらず、独自の手法を使っている。

 AndroidがLinuxカーネルを採用した利用の1つとして、「既に多くのデバイスドライバをサポートしているからではないか」と推察。AndroidはApacheライセンスがベースになっているものが多く、BSD系列のカーネルの方が「ライセンス的には統一できそう」にもかかわらず、Linuxカーネルの方がデバイスドライバのサポートが多いので採用したのではないかと予想する。その中でAndroid特有のカーネルドライバとしては「binder」「ashmem」「wakelock」「logger」などがある。

 さて、Androidの全てのソースコードは、Googleの特定のサービスを除いて全てダウンロード提供されており、ビルドは容易だ。「高速なPCならフルビルドは20分ぐらい」(同)だという。「ほぼ全てのソースが手に入って、簡単なスクリプトでビルドでき、破綻せずに管理されているのがすごい」と小林氏は話す。

 Androidを「Linuxだがカーネルしか使っておらず、実際は随分と違う」と指摘。Android特有のデバイスドライバの拡張や、小さなシステムとして動作するようなチューニングがされているなど「他のどれ(OS)とも似ていない」という。

 「なぜAndroidなのか?」と問い掛ける。Androidではシステムとアプリが「きれいに分かれている」という特徴があり、サードパーティーによるアプリのダウンロード、コミュニティーの存在、そして簡単にアプリがアップグレード・バグフィックスできる点に加え、HTML5にも対応した高機能なブラウザコアを備える点などがメリットとして挙げられる。

 別のプラットフォームの開発者がAndroidアプリを開発する場合、「これまでの資産のどの部分を生かして、どの部分を捨て去るかという選択が必要になる」と話す。その検討には、Androidでアプリを実行するときのオーバーヘッド、ストレージやメモリの使用量、OS自体のバージョンアップが早いことによるその追従といった観点に加え、「Androidそのものにはなるべく手を触れずにアプリを作る視点も考える必要がある」という。

 アプリを移植する場合、従来のバイナリがそのまま動作する場合がある。これはARMのEABIを使っているためで、例えばARM上で動作するUbuntuなどのように同じABI(Application Binary Interface)であれば、全てのファイルをコピーすれば動作してしまう。経験によると、Rubyが再コンパイルせずにそのまま動作したそうだ。ただし、これは非常に簡単な手法だが、Androidのシステム本体とは別にライブラリを導入するため、無駄になってしまう。また、全ての場合で必ず動作するとは限らない。

 リビルドする場合は、Androidのソースをテンプレートとして用い、いらないファイルを省いた上で「Android.mk」を修正してビルドすればいい。メモリやストレージの利用量は最小限に抑えられるメリットはあるが、Cのライブラリが簡略化されていたり、マルチバイトライブラリのサポートが最小限だったり、「IPv6のサポートがよくない」といった問題があるそうだ。