Linuxカーネルに組み込む方法の中で、Linuxベースのセキュリティ裁量モデル(DAC)の拡張を目的としたさまざまなセキュリティモデルを統合するように設計されたLinux Security Modulesフレームワーク(以下、LSM)の使用に基づく方法に注目する価値があります。
LSMのLinuxカーネル実装について
後で説明するLSM実装の機能により、このサブシステムを使用してLinuxカーネルの主要なメカニズムに組み込むことができます。 同時に、LSMの主な目的は、現在のLinuxセキュリティモデルを拡張するための統一されたインターフェイスをユーザーに提供することであるため、これに関連する制限があることに留意する必要があります。
LSMサブシステムのアーキテクチャは単純です。 技術的には、OSのカーネルにインストールされたフックのセットで、さまざまな操作中にシステムが呼び出すカスタムハンドラーを実装するためのインターフェイスを提供します。 基本的なセキュリティモデル記述子構造は
security_operations
構造であり、その説明はinclude / linux / security.hファイルにあります。
struct security_operations { char name[SECURITY_NAME_MAX + 1]; ... int inode_permission(struct inode * inode, int mask); ... }
ご覧のように、セキュリティモデルは次のパラメーターによって記述されます:名前とハンドラー関数へのポインターのセット。その本質は、実装されたセキュリティモデルの主要な機能です-資格、ロールベース、または他のモデルです。 ここでの主なことは、オブジェクトへのサブジェクトのアクセスの実現を担当するカーネルコードのセクションの実行中に制御をインターセプトする機能です。
システムの重要な場所に配置されているLSMフックは、現在のセキュリティモデルの1つまたは別の機能を特別に設計された呼び出しであり、変更する可能性は残されています。 技術的には、これは追加のエンティティ(現在アクティブなsecurity_ops セキュリティモデルへのポインタ)を導入することで実装されます。
static struct security_o perations * security_ops; static struct security_o perations default_security_ops = { . name = "default", };
システム起動時のこのポインターの初期値は、 default_security_ops構造体で記述され、システムのデフォルト動作の実装を含む標準セキュリティモデルに対応しています。 同時に、ハンドラー関数の入力は最小限です。 ただし、システムの操作中に別のモデルをアクティブにする必要が生じた場合は、このポインターの内容を単純に置き換えることでこれを実行できます。 以下は、対応するフックで
security_ops
を使用する例です。
int security_inode_permission(struct inode *inode, int mask) { if (unlikely(IS_PRIVATE(inode))) return 0; return security_ops->inode_permission(inode, mask); }
ご覧のとおり、
inode_permission
ハンドラー
inode_permission
は、上記に対応する
security_ops
ポインターの値を使用して間接的に
inode_permission
ます。 良い例は、ファイルシステムオブジェクトへの現在のプロセス(サブジェクト)のアクセスを制御するカーネル仮想ファイルシステム(VFS)の重要な機能であるinode_permissionの例を使用したアクセス制御実装の図です。
int inode_permission(struct inode *inode, int mask) { int retval; retval = sb_permission(inode->i_sb, inode, mask); if (retval) return retval; return __inode_permission(inode, mask); } int __inode_permission(struct inode *inode, int mask) { int retval; if (unlikely(mask & MAY_WRITE)) { /* * Nobody gets write access to an immutable file. */ if (IS_IMMUTABLE(inode)) return -EACCES; } retval = do_inode_permission(inode, mask); if (retval) return retval; retval = devcgroup_inode_permission(inode, mask); if (retval) return retval; return security_inode_permission(inode, mask); }
security_inode_permission
LSMフックは機能を終了し、ファイルシステムの
inode
構造で表されるファイル(オブジェクト)へのプロセス(サブジェクト)アクセスをチェックする段階の最後の行です。 したがって、以前のすべてのチェックが正常に完了した場合にのみ機能します。これは、セキュリティモジュールが基本システムモデルを置き換えず、それを補完および拡張するだけのLSMコンセプトに対応します。
LSMの簡単な説明を要約すると、さまざまな期間におけるこのフレームワークの開発のダイナミクスを反映した興味深い統計を検討する価値があります。 これらの目的のために特に収集された情報は、カーネルバージョンに応じたLSMフックの総数を反映するグラフに表示されます。
まず、その数は注目に値します。 実際、バージョン
v2.6.11
のカーネルに134個のフックがある場合、バージョン3.8のカーネルには既に189個のフックがあり、これはLSMのカーネルへの統合の深さの指標です。 第二に、フックの数の変化のダイナミクスは、バージョン
v2.6.34
より前のLSMの急速な発展と、サブシステムの成熟度、相対的な完全性、およびアーキテクチャの安定性の指標である安定化を示します。
LSMを使用した埋め込みについて
基礎となるLinuxカーネルセキュリティモデルを拡張する手段として、LSMはその不可欠なコンポーネントではありません。 カーネル内のこのフレームワークの存在は、
CONFIG_SECURITY
構成変数の状態によって決定され、コンパイル段階で設定されます。 実際には、これは、ターゲットシステムのコアをLSMなしで構築できることを意味します。 それにもかかわらず、他の場合では、この機能を埋め込みに使用することは非常に実用的であるように見えますが、LSM自体のアーキテクチャに主に関連する独自の特性があります。 実際、埋め込み機能は、カーネルLSMフックでのカバレッジの完全性によって決まります。 言い換えれば、 それが提供されている場所でのみ統合することが可能です。
アーキテクチャに従って、LSMメカニズムの機能を保証するLinuxカーネルの主要なオブジェクトは
security_ops
ポインターです。これは、現在の(アクティブな)LSMモデルの記述子構造のアドレスを格納するカーネルメモリセルです。 さらに、モデルへのアクセスに関連するすべての操作はこのポインターを介して実行されるため、埋め込みにはこの値を制御できることが必要かつ十分であると主張できます。
カーネルモジュールによるLSMモデルの実装について言えば、LinuxカーネルへのLSMに課せられた制限の段階的導入に関連する機能があることに注意する価値があります。 したがって、セキュリティ上の理由から、システムの動作中に現在のセキュリティモデルを変更できるように、インターフェイスはカーネルから順次除外されました。
- バージョン
v2.6.24
以降、security_ops
ポインターはエクスポートされず、static
としてマークされstatic
(コミット189b3b1c89761054fee3438f063d7f257306e2d8を参照)。 - バージョンv2.6.35以降、register_security関数はエクスポートされず、__initとしてマークされます。これは、実行後にコードを含むメモリ領域をアンロードすることを意味します(commit c1e992b99603a84d7debb188542b64f2d9232c07を参照)。
これらの機能は、埋め込み用のLSMの範囲を制限するように設計されていますが、実際には重要ではなく、それらを回避する方法があります。これについては後で説明します。
埋め込みの実用的な側面
カーネル
v2.6.34
、システムの動作中に現在のセキュリティモデルを変更する定期的な機能
v2.6.34
ないことに注意してください。 ただし、現在のモデルポインター
security_ops
アドレスを決定する方法が見つかった場合、この状況は克服できます。 簡単で信頼できる方法の1つは、カーネルコード、つまりこのポインターが使用される関数の1つを逆アセンブルすることです。 実際、
gdb
デバッガーを使用して64ビットx86システム用に取得したエクスポートされたsecurity_sb_copy_dataフック関数のリストを例として検討する価値があります。
int security_sb_copy_data(char *orig, char *copy) { return security_ops->sb_copy_data(orig, copy); } EXPORT_SYMBOL(security_sb_copy_data);
# gdb vmlinux /proc/kcore (gdb) x/7i security_sb_copy_data 0xffffffff811f61b0: push %rbp 0xffffffff811f61b1: mov %rsp,%rbp 0xffffffff811f61b4: data32 data32 data32 xchg %ax,%ax 0xffffffff811f61b9: mov 0x881690(%rip),%rax # 0xffffffff81a77850 0xffffffff811f61c0: callq *0x98(%rax) 0xffffffff811f61c6: pop %rbp 0xffffffff811f61c7: retq (gdb) x/s* 0xffffffff81a77850 0xffffffff81850fa0: "default"
ご覧のとおり、ディスパッチ命令
callq *0x98(%rax)
は、
%rax
格納されたポインターを基準にしてオフセット
0x98
で
sb_copy_data
ハンドラー
sb_copy_data
を呼び出します。 つまり、
%rax
には
security_ops
も含まれてい
security_ops
。 したがって、このポインタを取得するには、この関数の先頭から
mov 0x881690(%rip),%rax
を見つけるまでコマンドをスキャンし、目的の値を
%rax
に読み込んでオペランドの簡単な分析を実行する必要があります。 、必要なポインターを取得します。 以下は、これをudis86逆アセンブラーを使用してx86で実行できるようにするコードです。
static void * get_lsm_entry(void) { /* this one is exported */ return (void *)&security_sb_copy_data; } static struct security_operations ** get_lsm_sop(void) { ud_t ud; void * entry = get_lsm_entry(), * result = NULL; ud_initialize(&ud, BITS_PER_LONG, UD_VENDOR_ANY, entry, 128); while (ud_disassemble(&ud) && ud.mnemonic != UD_Iret) { if (ud.mnemonic == UD_Imov && \ ud.operand[0].type == UD_OP_REG && ud.operand[1].type == UD_OP_MEM) { #ifdef CONFIG_X86_64 result = entry + ud_insn_off(&ud) + ud_insn_len(&ud); #endif result = result + ud.operand[1].lval.sdword; break; } } return result; }
したがって、
security_ops
ポインターへのポインターを受け取ったら、このポインターの値を置き換えるだけで、アクティブなセキュリティモデルを独自の実装に置き換えることができます。 例として、
inode_permission
関数を置き換えるfakelsmプロジェクトのコードを
inode_permission
ます。
おわりに
結論として、次のことを言ってください。 カーネルの外部でLSMを使用する際に順次導入される制限にもかかわらず、このフレームワークは興味深いものです。 カーネルに埋め込む絶好の機会を提供します。 ただし、その機能は、LSMフックでのカーネルコードのカバレッジの程度によって制限されることを理解する必要があります。 また、最新のカーネルは非常に多数ありますが、これらの制限は明らかです。
さらに、LSMアーキテクチャの概念自体は、単純で効率的であるため、安全ではないことが重要です。 実際、拡張カーネルセキュリティモデル全体は、単一のポインタ
security_ops
基づいています!
読むために
- Linuxセキュリティモジュール
- udis86のドキュメント
- GrsecurityおよびRSBAC LSM批判