1. GeekOut
  2. コラム
  3. 低レイヤーの学び方 ── システムソフトウェアの世界は「今すぐ役に立つものが全て」ではない
ログアウトしました

低レイヤーの学び方 ── システムソフトウェアの世界は「今すぐ役に立つものが全て」ではない

f:id:blog-media:20180718111615j:plain

はじめまして、木村 廉と申します。現在神戸大学大学院の修士2年生で、システムソフトウェアの脆弱性検出やself protectionについて研究しています。

§

実はこのコラム執筆のお誘いをいただいた時、はじめはお受けするかどうか少し迷いました。というのも、「GeekOut」の過去のコラムを見ると、執筆者の皆さんは最前線で活躍されている方ばかりで、一介の学生の私では見劣りするような気がしたからです。

しかしながら、私もエンジニアの端くれですので、他のエンジニアと差別化できる強みも多少は持っています。そしてそれは、幸いにも他の人とかぶりづらいマニアックな部類のもので、参考にできる資料も多くありません。

その強みとは、OSやハイパーバイザ(コンピュータを仮想化するための制御ソフトウェア)といった、基本的な制御を行うシステムソフトウェアを開発したり、それに手を入れたりすることです。いわゆる“低レイヤー”と呼ばれる分野です。

あまり目立つ分野ではないため、現状では誰もなかなか取り上げてくれません。インターネット上で探せば断片的な情報は見つけられますが、「どうやって学べばよいか」という学習方法の指南や、実際にその知識や技術をどう生かしていけるのか、といったロードマップのような存在はほぼ皆無なわけです。

というわけで、学生の私でも何も発信しないよりは……ということで、今回お引き受けしました。

特にこれからは、IoTなどの分野において一見ヘンテコなデバイスと制御ソフトウェアが走り回るような時代ですし、多種多様なシステムトラブルに見舞われるようになってくると思います。そんな時代ですから、OSやファームウェアなどのシステムソフトウェアに関する理解があれば、きっと大きなアドバンテージになるでしょう。

このコラムでは私の経験を基に、OS、ファームウェア、仮想マシンモニターといったシステムソフトウェアのハックスキルの学び方、生かし方について紹介します。組み込み開発のような職業に就いている方から、Webエンジニア、インフラエンジニアの方まで、このレイヤーの魅力が少しでもお伝えできれば幸いです。

「システムソフトウェアについて学ぶ」ことの意義

そもそもシステムソフトウェアについて学習するとは一体どういうことでしょうか。

大学の講義で説明されるようなOSの一般的なアーキテクチャや歴史については誰でも簡単に学べますが、今回焦点を当てるのは、そういった体系だった知識ではありません。実際の業務でのエンジニアリングにおいて、例えば、

  • 大規模なシステムを運用するためにLinuxサーバーをカーネルレベルでチューニングする必要がある場合
  • 新しいデバイスを開発してOSやファームウェアを組み込む場合
  • 高度なセキュリティインシデントに対応するために、エクスプロイト(システムの脆弱性を攻撃するプログラム)やルートキット(攻撃者が攻撃対象のコンピュータに侵入し、コントロールを行うために必要な、複数の不正プログラム群のセット)の調査を行う場合

……などに使える技術を指します。もちろん、業務内容によってカバーすべきジャンルは異なりますが、基本的な能力としてカーネルのソースコードを読む力やCPU、ネットワークカードの挙動を仕様書から把握できる力を持っていれば、頭を抱えるようなシステムトラブルやセキュリティインシデントに遭遇しても、対策を立てる見通しはかなり良くなるはずです。

しかしこういったマニアックなレイヤーの知識について書かれた資料は少なく、常に暗中模索な状態です。そのため、勉強しようにも「一体何から始めればいいのか分からない」という声をよく聞きます。

以前私がブログで書いた「低レイヤーの歩き方」という記事では、OSや仮想マシン、コンパイラといったジャンルごとに、入門の取っ掛かりとして参考になりそうな資料を挙げていきました。

rkx1209.hatenablog.com

しかしこの記事はあくまで資料の掲示を目的としたリンク集に近く、学習方法そのものについてはあまり触れていません。

そこで、このコラムでは具体的な書籍や資料の紹介を割愛する代わりに、方法論についてまとめて話をします。「これが絶対的なやり方だ」というものはなく、あくまで自分自身の経験を基に得たノウハウを共有するのが目的です。

「今役に立つもの」が全てではない。 ボトムアップ学習のすすめ

システムソフトウェアは“単に知っているだけ”という状態と“自分でモノにしている”状態との差が非常に大きい世界です。知識として知るだけであれば、OSの構造やCPUの仕様程度なら関連資料を流し読みするだけで、そこそこ身に付けられます。

しかし実際のエンジニアリングで求められるのは、カーネルのソースコードレベルでの理解やチューニング、拡張機能の実装といった、より実践的なスキルです。このギャップを埋めるためには、主に2つの学習方法があると私は考えています。

1.トップダウン方式

まず一つはトップダウン方式です。例えばサーバーのチューニングに際してOOM Killer(Linux系のOSで、システムが必要なメモリ領域を確保できなくなった場合、既存の稼働中のプロセスを強制終了させてメモリを確保するLinuxカーネルの仕組み)やネットワークスタックの挙動を調査するために、Linuxカーネルの該当箇所のソースコードを読む、あるいはPCIデバイスドライバを開発するために関連するカーネルAPIの使い方を覚えるなど、与えられた課題を解決するために必要な技術のみを、トップダウンで身に付けていく方法です。

非常に合理的で効率の良い方法です。しかし、欠点もあります。例えば今まで見たことのないカーネルクラッシュに遭遇した場合、クラッシュログをGoogle検索にかけるだけでは正確な原因は特定できません。コールスタックを読んでエラーの発生する処理を見極める必要がありますが、これはLinuxの実装をある程度理解している必要があります。また、既存のカーネルAPIのみでは実現できない機能を実装する場合も、カーネル本体に手を加える必要が出てくるかもしれません。

こういう場合は当然、課題ドリブンなトップダウン方式では対応しきれず、それなりの「下地」が要求されます。そこで必要になってくるのが「ボトムアップ方式」の学習方法です。

2.ボトムアップ方式

ボトムアップ方式の学習とは、「いつか役に立つかもしれない」知識を下積みしておく学習方法です。

例としては、「Linuxカーネルのチューニングや運用を頻繁に行うのであれば、前もって関連しそうなサブシステムのソースコードを読んでおく」「複雑な組み込み開発に携わる予定があるのであれば、まずは簡単なシステムソフトウェアを自分で作ってみる」など、可能な限り守備範囲を広げておくといったようなことです。一見遠回りな方法ですが、私の経験上、解決の糸口すら見えず立ち往生するよりは、はるかに効率的な方法です。

実際私も、初期の学習にはボトムアップな方法を取っていました。学生ですので業務という縛りはなく、多少生産性のない作業をしてもとがめられないわけですから、かなり無茶なこことまでやってみました。特に目的もないままにOSやプログラミング言語を作ったり、LinuxやAndroidのコードを読んで機能を付け足してみたり、オーバーエンジニアリングのオンパレードでした。

もちろんこれら全ての知識が、今の活動に100%役立っているわけではありません。しかし、技術的課題に直面した時、さまざまなアプローチの方法が思い浮かぶのは、この時に築いた「下地」のおかげです。特にこのジャンルは、先にも述べた通り参考資料が少ないですから、持っておく引き出しは多いに越したことはありません。

積極的な情報収集と関連付け

とはいえ、せっかく時間をかけて学ぶのであれば、自分に関係しそうなテーマに優先的に取り組みたいですよね。完全に無駄になるとあらかじめ分かっている知識を学んでも時間の浪費になってしまいますので、この情報は自分の役に立ちそうか、そうでないかを見極める力が必要です。

そこでおすすめするのがRSSリーダーやSNSを利用した情報収集です。PhoronixredditLWN.netといったニュースフィードを購読したり、関連する業界に所属する人のSNSアカウントをフォローしたりして、彼らがシェアしてくれる情報に目を通してみましょう。

この手のニュースサイトでは、大抵の場合単なる技術概説にとどまらず、開発された目的や、実際にどういった場面で使われているのかといった情報にも言及してくれます。「Facebookが自社のMySQLデータベース処理高速化のためのSSDキャッシュシステムとして、FlashCacheというカーネルモジュールを開発した」というように、背景や目的、それを実現するための技術的手段について網羅してくれますので、そこから自分が学ぶべきテーマを見つけるための最適な情報源となってくれます。

一体何から勉強し始めればよいのか分からないという方は、まずはさまざまなニュースフィードを購読してみることをおすすめします。一例として私の場合、上に挙げたサイトに加えて、セキュリティ業界のニュースを収集してくれるpiyologThe RegisterPhrack Magazineをはじめ、Twitterの専用リストなども使って情報収集を行い、興味がありそうなテーマを見つけた時は一次ソースまで詳細に調べるようにしています。最近ではリバースエンジニアリングの形式的手法について興味があるため、Möbius Strip Reverse Engineeringというブログを購読したり、ファームウェアのセキュリティを学ぶためにFirmware Securityに目を通したりしていますが、これらは上記のニュースサイトやTwitterのつぶやきからヒントを得て見つけたものです。

コミュニケーションの重要性

どうしても分からないことがあれば、素直に人に質問しましょう。特にシステムソフトウェアという複雑怪奇なものを扱っていると、一体この機能は何のために作られたのか、なぜこれでうまく動くのか、全く見当も付かない場合が多々あります。

そういう時は素直にメーリングリストやIRCを使って、開発コミュニティに質問を投げてしまうのが吉です。私はこれが日本人技術者に最も欠けている力ではないかと思います。

もちろん、開発者の方々も暇ではないので、質の低い質問を投げるのは避けるべきです。何でも聞けばよいという意味ではなく、単純な調査では把握しきれない開発者の思惑や、設計思想を聞き出す有意義な場として、コミュニティを活用するべきだということです。

また、システムの改善案や新しい機能の追加を思いついた時は、修正パッチやRFC(Request for Comment)として積極的に投稿していくと良いと思います。

コミュニティの規模にもよりますが、よほどのことがない限り、それなりの反応が返ってきます。有意義な内容であればあるほど、多くの人たちから意見をもらえますし、次期バージョンに追加されるかもしれない有力な機能としてニュースサイトに掲載されることさえあります。

いきなりパッチを送るのは気が引けるという方は、バグやクラッシュレポートを送るだけでも構わないと思います。実際私も最初の頃はただのバグレポートソースコードに関する質問から始めていき、徐々にパッチを書いて送ったり、新しい機能の提案をしたりするようになりました。

おわりに

ここまでシステムソフトウェアの学習方法について、ポイントごとに説明してきました。大きくまとめると、課題解決のためのハックスキルをその都度学ぶだけではいずれ限界が来るため、ある程度の下地が必要であること、そのためには必要な情報を仕分ける力やオープンな場で議論を行えるだけの積極性も求められるということです。

私はシステムプログラミングを始めて5年になりますが、未だに解決の糸口が見えない無理難題にぶつかることがあります。そういう場合は上記の方法を素直に実践しています。

明らかに知識不足であると感じた時は、関連分野を勉強して下地を作り直しますし、特定のソフトウェアに依存した問題であれば、開発者にコンタクトを取って助言を受けたりもしています。

システムソフトウェアというものは泥臭い作業の集大成ですので、短期間に都合よく事を進めるというのはなかなかできません。常にこういった素朴な作業の繰り返しになります。

画期的なハックも突然湧いて出るわけではなくて、多くの知識や経験に裏付けされた結果であることがほとんどです。特にシステムソフトウェアのような複雑なものを扱う際は、確実に地に足をつけて進んでいくのが良いと思います。

地道な作業を恐れず、着実に力を付けていくのが一番の近道と言えるでしょう。

 

木村 廉(きむら・れん)

 

木村 廉

神戸大学大学院修士課程2年目に在籍。2018年10月よりカーネギーメロン大学(CMU)にて客員研究員として勤務予定。OSや仮想マシン、ファームウェアといったシステムソフトウェアに対する攻撃とその対策技術に関心がある。
主な活動にIPA未踏スーパークリエイター(2016)、Google Summer of Code(2017)、IPAセキュリティキャンプ講師(2017)がある。趣味はバイナリハック。

About | Ren Kimura

  • このエントリーをはてなブックマークに追加

関連記事

低レイヤーの学び方 ── システムソフトウェアの世界は「今すぐ役に立つものが全て」ではない
「ITをITで支援する」MSP事業者が、変革する開発・運用で果たす役割──スキルの価値が10年で消える世界においてエンジニアはどうあるべきか