AppArmor Detail

移動先: 案内, 検索


AppArmorのデザイン

AppArmorは、アプリケーションのセキュリティ問題を解決するためにデザイン(設計)されています。AppArmorは、攻撃者がアプリケーションに予期しない動作をさせることを確実に防止します。それは単純なことのように聞こえますが、実際には非常に難しいのです。アプリケーションが仕様どおりに動作することはテストできますが、通常、不正なinput(訳注:ここではアプリケーションに対する想定外の操作、命令程度に解釈してください)というものには限りがないので、アプリケーションが不正なinputが行われた場合にも決して仕様から外れた動作をしない、ということはテストできないからです。Ivan Arceは簡潔にこう表現しました。「信頼できるソフトウェアは、想定どおりの動作をする。安全なソフトウェアは、想定どおりの動作をする――そしてそれ以外は何もしない。

ソフトウェアをコンパイルする段階において、ソースコードやバイナリ・ファイルに潜在する脆弱性を検査するツールは存在します。しかし、そうした検査手法は、理論的、そして実践的な理由から不完全なものであり、実施も困難です。さらに経済的、社会的理由から、こうしたツールを利用し、適切な処置が行われることはまれなのです。結果として、ほとんどのソフトウェアは多くの潜在的バグを抱えており、しかもそうしたバグの大半が攻撃者による不正な操作を許してしまいます。常にバグのないソフトウェアだけが供給されるのであれば、セキュリティを維持するのは簡単でしょう。しかし、そのアプローチは供給側に問題があるです :)。

AppArmorの目指すところ

誤った挙動をする可能性のあるソフトウェアからシステムを守るためには、アプリケーションに最小権限という原則を適用しなくてはなりません。これは、アプリケーションの動作中つねに、動作に必要最小限のリソースにだけアクセスを許可するという制限をかけるというものです。したがって、もしアプリケーションが不正に利用されてしまった場合でも、被害を最小限に食い止めることができます。しかし、同時に、安全を確保するための特権の制限(訳注:たとえroot権限が奪取されても、最小権限という制限を回避できないようにすること)や透過性、高速性も必要です。

  • 安全性 - アプリケーションがこの制限を回避することができないこと。
  • 高速性 - パフォーマンスのオーバーヘッドはごくわずかであること。
  • 透過性 - ごくわずかな変更だけで、ソフトウェアやユーザーがこれまでどおりに稼働/行動できること。

安全性は、セキュリティがまやかしのものにならないようにするために重要です。また、面倒で使いづらいためにセキュリティ機能をオフ(無効)にされてしまうのは、セキュリティ上最悪ですから、透過性や高速性も大切です。続いて、AppArmorがどのように安全性、パフォーマンス、そして透過性を実現しているのかを説明します。

LSM(Linux Security Modules Interface)を通じたセキュリティ

(回避不可能な)セキュリティを実現するためには、AppArmorのような仲介手段(mediation methods)はカーネル内部に組み込まれていなければなりません。元々、AppArmorはカーネル・パッチでしたが、特にエンタープライズ(企業)ユーザーにとっては、それが配布やシステムへの導入における大きな負担となっていました。カーネル・パッチを必要としないカーネル・レベルのセキュリティを実現するため、イミュニクス社(ノベルに買収される前のAppArmorの開発元)は、Linux 2.6カーネルでLSM(Linux Security Modules)インターフェースと呼ばれる機構を開発しました。LSMは、カーネル・モジュールに効率的なアクセスコントロールを仲介できるようにカーネルAPIを提供します。その他のLSM開発参加者には、SELinuxコミュニティやIBM、そしてさまざまなオープンソース・コミュニティの開発者たちが含まれます。

ライブラリなど、カーネル以外のレイヤーにおける仲介は、それを回避することを可能にしてしまいます。仮に、最小権限によって動作が制限されたアプリケーションであっても、攻撃者が任意のコードを実行できる(バッファ・オーバーフローなどの手段によって)ならば、彼らはライブラリを使わず、仲介を回避して直接カーネルを呼び出すでしょう。さらに言うと、カーネルの奥深くで行われるAppArmorのような仲介は、システムコールの遮断よりも良いものです。安全な仲介はsyscall tableの置き換え(as is done in Systrace)により実現されます。ただし、それは3つの重大な問題を誘引します:

  • コード詰まり(Code Embolism):カーネルは、基礎的な機能(インフラストラクチャー)をたくさん備えています。例えば、「foo」という名のファイルを開けという要求があった場合に、カレント・ディレクトリ(現在作業中のディレクトリ)などを考慮したうえで固有のinode番号に変換するような機能のことです。しかし、システムコールが遮断されているとその情報が利用できません。そこで、仲介システムは「foo」へのアクセスが許可されているかどうかについての重要な判断を行う前に、まず変換を行うためのコードを複製しなければなりません。なお悪いことに、この変換は現在2回行われるようになっており、パフォーマンスを悪化させています。
  • SMP Safety: The name of the file being requested is in user-accessable memory, and thus vulnerable to change between the time the mediation module checks the access and the time the kernel grants the access. So the mediation module might see an access request for the file "foo", and then after it is approved the requestor changes the request to "../bar". This attack is especially likely on SMP machines, which will become most machines as multicore chips proliferate.
  • Linus:Linusは、GPL絡みの理由でLinux Kernel 2.6からsyscall tableを再読み込みする機能を削除することに決めました。だから、システムコールの介入はkernelへのパッチの適用が必要だという問題があります。

So instead of system call mediation, LSM inserts hooks deep into the kernel. Wherever a request by a user level process leads to access to an important deep kernel data structure, such as task descriptors or inodes, the LSM hook makes an up-call to whatever LSM module is loaded, asking "is this ok?" The LSM module considers the situation, makes its access control decision, and sends back a "yes" or "no" answer to the kernel, which then either performs the access or returns an error to the requestor. Thus access control technologies like SELinux and AppArmor can do their work as loadable modules, without requiring constant patching of the kernel.

Performance Through Simplicity

To achieve speed, AppArmor uses a very simple security model so that checking can be done quickly. In particular, security policies are very small, so that they can be fully loaded into kernel memory, eliminating the need for a 2-level caching architecture of policy storage.

Transparancy Through Familiarity

To achieve transparency, AppArmor uses all-classical UNIX security semantics, but applies them to programs. An AppArmor policy specifies the set of POSIX.1e capabilities that a program can have, and specifies the set of files it can access. The POSIX.1e capabilities are specified by name. The files are specified by absolute path names, including embedding shell-syntax wild cards, followed by access modes (R, W, and X, with a bit of embellishment). So an AppArmor policy to confine ntpd (the network time protocol daemon) looks like this:

/usr/sbin/ntpd {
 #include <abstractions/base>
 #include <abstractions/nameservice>
 #include <program-chunks/ntpd>
 capability ipc_lock,
 capability net_bind_service,
 capability sys_time,
 capability sys_chroot,
 capability setuid,
 /etc/ntp.conf             r,
 /etc/ntp/drift*           rwl,
 /etc/ntp/keys             r,
 /etc/ntp/step-tickers     r,
 /tmp/ntp*                 rwl,
 /usr/sbin/ntpd            rix,
 /var/log/ntp              w,
 /var/log/ntp.log          w,
 /var/run/ntpd.pid         w,
 /var/lib/ntp/drift        rwl,
 /var/lib/ntp/drift.TEMP   rwl,
 /var/lib/ntp/var/run/ntp/ntpd.pid w,
 /var/lib/ntp/drift/ntp.drift      r,
 /drift/ntp.drift.TEMP     rwl,
 /drift/ntp.drift          rwl,
}


From here, it would be relatively straightforward to hand-craft security policy for applications through a combination of expert knowledge and trial and error. However, that would be so tedious that the vast majority of developers and users would refuse to put in the work. To further improve transparency, AppArmor includes a "learning mode" to allow policy to be built by running the application and observing what it does. In learning mode, the rules are not actually enforced, but violations are logged, and process forking is tracked, so that the log of an application's execution builds up a characteristic description of the application's activities. AppArmor includes a log analysis program that scans the log, prompts the user with questions, and automatically creates a program profile. Learning mode and the log analyzer are also capable of incremental improvement of the profile if one already exists, but omits some necessary rules.

Application Security and System Security

An individual application can be secured using an individual profile, but how to secure a system? A vital question in securing any system is "against what threats?" We could profile all of the programs on the system, but that would be a lot of effort, and in most cases unnecessary. For instance, consider the network threat model: we want to prevent remote network attackers from gaining control of the system. To prevent such an attack, we need to ensure that all programs that communicate with the network have an AppArmor profile. If we profile all applications that connect to the network, then the AppArmor profiles completely control everything that a network attacker could do to the system.

Note: When an AppArmor profile grants permission to execute another program, it specifies whether the child executes in its own profile (denoted px), executes in the same profile as the parent inheriting the parent's profile, (denoted ix) or whether the child gets to execute unconstrained (denoted ux). The px permission should be used for major programs that broker access to data, such as Apache executing Sendmail to send some mail. The ix permission should be used for smaller, utility programs that operate on whatever data the parent has at hand, such as a shell script executing cp to copy a file. The ux permission is very dangerous, and should be used carefully to allow administrative access that is not regulated by AppArmor, such as the ultimate system administrator's shell executed from the SSH daemon.

Since the network threat model is so common a concern, AppArmor comes with a system analyzer called unconfined, which scans the machine for open network ports, finds the programs listening to those open network ports, and lists the profiles wrapped around those programs, if any. If unconfined reports that all open network ports lead to AppArmor profiles, then it is the case that these profiles fully define the worst case the attacker could impose on the machine.

Similarly, to protect a workstation against network attack, all of the programs that process network input should be profiled. Some of these programs have persistent open network ports, such as ssh clients. Some have transient open network ports, such as web browsers, mail clients, and IM clients. And some such programs have no network ports, but none the less process network input with considerable security risks, such as the OpenOffice suite, which is often asked to immediately open .doc files that are attached to incoming e-mail messages. However, one still need not profile all of the programs on the workstation, only those that process network input.

In a different situation, to protect a kiosk workstation against attacks from users, all of the programs that accept keyboard and mouse input should be profiled, as well as any other device readers such as bar codes and mag stripe readers. This "keyboard threat model" is very similar to the network threat model above, but with the threat coming from local IO devices like the keyboard and card reader, rather than the network interfaces.