Androidオペレーティングシステムのセキュリティの基本。 Application Frameworkレベルでのセキュリティ。 バインダーIPC

エントリー



短い休憩の後、Androidオペレーティングシステムでセキュリティを確保する方法の基本原則を説明し続けます。 今日は、アプリケーションフレームワークレベルでのセキュリティについて説明します。 しかし、このトピックを理解するには、最初にAndroidがプロセス間通信(プロセス間通信(IPC))のメカニズムを実装する方法を考慮する必要があります。 このメカニズムはIPCバインダーと呼ばれ、今日はその機能を検討します。 興味のある方、ようこそ!







記事一覧

以下は、このシリーズの私の記事へのリンクです。

  1. Androidオペレーティングシステムのセキュリティの基本。 コアレベル
  2. Androidオペレーティングシステムのセキュリティの基本。 ネイティブユーザースペース、パート1
  3. Androidオペレーティングシステムのセキュリティの基本。 ネイティブユーザースペース、パート2
  4. Androidオペレーティングシステムのセキュリティの基本。 Application Frameworkレベルでのセキュリティ。 バインダーIPC






なぜIPCバインダーが必要なのですか?



シリーズの最初の記事で書いたように、Androidの各アプリケーションは独自のサンドボックス(アプリケーションサンドボックス)で実行されます。 Androidのサンドボックスメカニズムは、各アプリケーションに一意のユーザーID(UID)グループID(GID)を割り当てることに基づいているため、このオペレーティングシステムの各アプリケーション(アプリケーションまたはアプリ)には独自の一意の非特権ユーザーがいます。 サイクルの最初の記事でこのトピックを検討しました。 同時に、システムのすべての重要なリソースの所有者は、名前と識別子がシステムに固定されている特権ユーザーです( system / core / include / private / android_filesystem_config.hを参照 )。 これらのユーザーに代わって起動されるシステムサービスは、関連する重要なシステムリソース(GPSデータなど)にアクセスできますが、通常のアプリケーションプロセスはこれらのリソースにアクセスできません。



ただし、アプリケーションはシステムサービスに「要求」してそのような情報を提供できる必要があり、後者はそのような情報をアプリケーションに提供できる必要があります。 アプリケーションとシステムサービスは異なるプロセスで実行されるため、このような交換を整理するには、オペレーティングシステムがプロセス間で情報を交換するためのメカニズムを提供する必要があります。 さらに、通常のアプリケーションでさえ、相互にやり取りする必要がある場合があります。 たとえば、電子メールクライアントは、画像ビューアにレターへのグラフィカルな添付ファイルを表示するように「求める」場合があります。



Androidでは、プロセス間の信号とデータの交換は、プロセス間通信バインダーフレームワークを使用して編成されます。 標準のSystem V IPCフレームワークはこのオペレーティングシステムではサポートされいません。特に、 Bionic libcにはヘッダーファイル<sys / ipc.h>、<sys / sem.h>、<sys / shm.h>、<sys / msg.hがありません。 >。 特定の場合(たとえば、Zygoteデーモンと対話するため)、 Unixドメインソケットが使用されます。 インテントを含むプロセス間の相互作用の他のすべての方法は、バインダーIPCを使用して実装されます。 このフレームワークを使用すると、リモートオブジェクトのメソッドをローカルであるかのように同期および非同期で呼び出したり、プロセス間でファイル記述子を交換したり、死へのリンク (特定のプロセスのバインダーが中断された場合の自動通知)などを行うことができます。





バインダーIPCはどのように機能しますか?



プロセス間の相互作用は、同期クライアントサーバーモデルによって編成されます。 クライアントは接続を開始し、サーバーからの応答を待ちます。 したがって、クライアントとサーバー間の対話は連続して発生します。 この設計により、開発者はリモートメソッドを同じプロセスにあるかのように呼び出すことができます。 これは、非同期メソッド呼び出しについて上で書いた内容と一致しないことに注意する価値があります。非同期呼び出しの場合、サーバーはすぐに空の応答をクライアントに返します。 バインダーを介したプロセス相互作用図を次の図に示します。 プロセスAで実行されるアプリケーション(クライアント)は、 プロセスBで実行されるサービスに実装されている機能にアクセスします







Binder内のクライアントとサーバー間のすべての対話は、特別なLinuxデバイスドライバー/デバイス/開発/バインダーを介して行われます。 記事「Androidオペレーティングシステムのセキュリティの基礎。 ネイティブユーザースペース、パート1」では 、システムブートプロセスを調べました。 initプロセスによって起動される最初のデーモンの1つは、Androidの外部デバイスマネージャーであるueventdです。 このサービスは、 起動時にueventd.rc構成ファイルを読み取り、外部デバイスを追加するイベントを再生します。 これらのイベントは、所有者(所有者)およびグループ(所有グループ)と同様に、デバイスのアクセス許可に対して設定されます。 次の例では、 / dev /バインダーに設定されている権限を確認できます。



... /dev/ashmem 0666 root root /dev/binder 0666 root root ...
      
      







ご覧のとおり、このデバイスのアクセス許可は0666に設定されています。これは、システムのすべてのユーザー(およびAndroidのさまざまなアプリケーションが一意のユーザーであることを覚えています)がこのデバイスへの書き込みと読み取りの権限を持っていることを意味します。 このドライバーと対話するために、 libbinderライブラリーが作成されました。 このライブラリを使用すると、ドライバーと対話するプロセスをアプリケーション開発者に対して透過的にすることができます。 特に、クライアントとサーバー間の対話は、クライアント側のプロキシ (プロキシ)とサーバー側のスタブを介して行われます(上の図を参照)。 プロキシとスタブは、ドライバーを介して送信されるデータとコマンドをマーシャリングする役割を果たします。 つまり プロキシは、クライアントから受信したデータとコマンドを、スタブが正しく読み取れるようにし(アンマーシャリング)、明確に理解できるようにマーシャリングします。 一般に、アプリケーション開発者は、アプリケーション用のスタブとプロキシも作成しません。 代わりに、AIDL言語を使用して記述されたインターフェイスを使用します。 このインターフェイスに基づいて、アプリケーションのコンパイル中に、スタブおよびプロキシ用のコードが生成されます(プロジェクトを検索して、その外観を確認できます)。



サーバー側では、クライアント要求ごとに個別のバインダーストリームが作成されます(上の図を参照)。 これらのスレッドは通常、バインダースレッド#nと呼ばれます。 ちなみに、メモリが適切に機能する場合、バインダーストリームの最大数は255で、単一のトランザクションでバインダーを介して送信できるデータの最大サイズは1Mbです。 これは、他のプロセスからデータを送信または受信するアプリケーションを開発する際に留意する必要があります。





サービスマネージャー



注意深い読者は、その前に、Androidがどのプロセスにデータを送信する必要があるかをどのように理解するかについては何も書いていなかったという事実に気付いているはずです。 技術的には、各バインダーサービスは32ビットトークンを割り当てます。これは、システムのすべてのプロセス内で一意です(ドライバーによって監視されます)。 このトークンは、サービスへのポインターとして使用されます。 クライアントにこのポインターがある場合、クライアントはサービスと対話できます。 しかし、最初に、クライアントはこの一意の値を取得する必要があります。



これを行うために、クライアントはBinder context managerを呼び出します 。これは、Androidの場合、 Service Manager (servicemanager)と呼ばれます。 Service Managerは、バインダートークンが事前に全員に知られている特別なサービスです。 このサービスのトークン値が0であることは驚くことではありません。バインダードライバーでは、このトークンを持つサービスを1つだけ登録できます。したがって、servicemanagerはシステムで起動される最初のサービスの1つです。 Service Managerは参照として表すことができます。 あなたはその名前のサービスを見つけたいと言い、その見返りにそのユニークなトークン番号を返します。それは後で必要なサービスと対話するために使用できます。 当然、サービスは最初にこの「ディレクトリ」に登録する必要があります。





安全性



Binderフレームワーク自体はシステムのセキュリティに責任を負いませんが、それを保証するメカニズムを提供します。 まず、各トランザクションのバインダードライバーは、トランザクションを開始するプロセスのPIDとUIDを書き込みます。 呼び出されたサービスは、この情報を使用して、要求を実行するかどうかを決定できます。 この情報は、メソッドandroid.os.Binder.getCallingUid()android.os.Binder.getCallingPid()を使用して取得できます。 第二に、バインダートークンはシステム内で一意であり、その値はアプリオリに知られていないため、それ自体をセキュリティトークンとして使用できます(たとえば、 この記事を参照 )。







おわりに



次のパートでは、許可について書く予定です。 資料は既にありますが、翻訳してお金を稼ぐ必要があります。 いつものように、コメントの興味深い質問や説明に感謝します。自分自身で誤解したかもしれません。





参照資料



  1. アレクサンダー・ガルゲンタによる「ディープ・ダイブ・イントゥ・バインダー・フレームワーク」
  2. Karim Yaghmourによる「組み込みAndroid」
  3. 「Androidバインダー。 Androidプロセス間通信» Thorsten Schreiber著



All Articles