第1回 知られざるセキュリティフレームワーク「LSM」の役割


村上 純一
株式会社フォティーンフォティ技術研究所
研究開発部 αUnit シニア・リサーチエンジニア
2008/3/18


ソースコードで見るLSMの動作

 では、SELinuxがどのようにLSMを利用しているのか、実際のコードを交えて見てみましょう。

 まず、カーネルソースをダウンロードして展開する必要があります。ここでは、CentOS 5.1での手順を紹介します。

% cd ~
% mkdir rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
% echo "%_topdir %(echo $HOME)/rpmbuild" > .rpmmacros
% sudo yum install rpm-build
% rpm -i http://mirror.centos.org/centos/5/updates/SRPMS/kernel-2.6.18-53.1.13.el5.src.rpm
% cd ~/rpmbuild/SPECS
% rpmbuild -bp --target=`uname -m` kernel-2.6.spec

 最近のCentOSでは、カーネル全体のソースコードは標準のパッケージには含まれていないため、別途ダウンロードして展開する必要があります。5.1以外のバージョンを利用している場合は、以下のURLを参考にインストールしてください。

関連リンク:
参考 http://wiki.centos.org/HowTos/I_need_the_Kernel_Source?highlight=%28kernel

 展開に成功すると、~/rpmbuild/BUILD/kernel-2.6.18以下にカーネル全体のソースコードが生成されます。セキュリティモジュールはカーネルソースのsecurity/以下に配置されています。security/security.cがLSMの本体であり、セキュリティモジュールの登録や登録解除など、セキュリティモジュールを管理するための機能が実装されています。

 セキュリティモジュールの登録を行うregister_security関数、登録解除の解除を行うunregister_security関数のコードをリスト12に示します。

 1 int register_security(struct security_operations *ops)
 2 {
 3     if (verify(ops)) {
 4         printk(KERN_DEBUG "%s could not verify "
 5             "security_operations structure.\n", __FUNCTION__);
 6         return -EINVAL;
 7     }
 8
 9     if (security_ops != &dummy_security_ops)
10         return -EAGAIN;
11
12     security_ops = ops;
13
14     return 0;
15 }
リスト1 register_security関数

 1 int unregister_security(struct security_operations *ops)
 2 {
 3     if (ops != security_ops) {
 4         printk(KERN_INFO "%s: trying to unregister "
 5             "a security_opts structure that is not "
 6             "registered, failing.\n", __FUNCTION__);
 7         return -EINVAL;
 8     }
 9
10     security_ops = &dummy_security_ops;
11
12     return 0;
13 }
リスト2 unregister_security関数

 register_security関数は、引数に指定されたsecurity_operations構造体のアドレスをチェックした後、グローバル変数であるsecurity_ops変数にセットします。dummy_security_opsは、LSMの初期化時にsecurity_ops変数にセットされる空のセキュリティモジュールです。security_operations構造体は、リスト3に示すようにセキュリティモジュールのコールバック関数のアドレスを保持する関数ポインタの集合になっています。

  1 struct security_operations {
  2     int (*ptrace) (struct task_struct * parent, struct task_struct * child);
  3     int (*capget) (struct task_struct * target,
  4         kernel_cap_t * effective,
  5         kernel_cap_t * inheritable, kernel_cap_t * permitted);
  6     int (*capset_check) (struct task_struct * target,
  7         kernel_cap_t * effective,
  8         kernel_cap_t * inheritable,
  9         kernel_cap_t * permitted);
 10     void (*capset_set) (struct task_struct * target,
 11         kernel_cap_t * effective,
 12         kernel_cap_t * inheritable,
 13         kernel_cap_t * permitted);
 14     int (*capable) (struct task_struct * tsk, int cap);
 15     int (*acct) (struct file * file);
 16     int (*sysctl) (struct ctl_table * table, int op);

……中略……

243     int (*key_permission)(key_ref_t key_ref,
244         struct task_struct *context,
245         key_perm_t perm);
246
247 #endif /* CONFIG_KEYS */
248
249 };
リスト3 security_operations構造体

 前述のsecurity_file_permission関数は、include/linux/security.hにおいてリスト4のように定義されています。カーネル内の処理は、security_ops変数を介してセキュリティモジュール内のコールバック関数を呼び出していることが分かります。

1 static inline int security_file_permission (struct file *file, int mask)
2 {
3     return security_ops->file_permission (file, mask);
4 }
リスト4 security_file_permission関数

 一方unregister_security関数は、単にsecurity_ops変数を、空のセキュリティモジュールであるdummy_security_opsのアドレスにセットし直すだけです。

図2
図2 vfs_readdir()関数からSELinuxのセキュリティモジュールが呼び出される

 SELinuxのコードは、security/selinux以下に配置されています。hooks.cに定義されているselinux_init関数が、SELinuxのセキュリティモジュールのエントリポイントです。コードをリスト5に示します。26行目で、先ほど説明したregister_security関数を呼び出していることが分かります。また引数に指定しているselinux_opsは、リスト6のようにSELinuxのコールバック関数群で初期化されています。

 1 static __init int selinux_init(void)
 2 {
 3     struct task_security_struct *tsec;
 4
 5     if (!selinux_enabled) {
 6         printk(KERN_INFO "SELinux: Disabled at boot.\n");
 7         return 0;
 8     }
 9
10     printk(KERN_INFO "SELinux: Initializing.\n");
11
12     /* Set the security state for the initial task. */
13     if (task_alloc_security(current))
14         panic("SELinux: Failed to initialize initial task.\n");
15     tsec = current->security;
16     tsec->osid = tsec->sid = SECINITSID_KERNEL;
17
18     sel_inode_cache = kmem_cache_create("selinux_inode_security",
19                 sizeof(struct inode_security_struct),
20                 0, SLAB_PANIC, NULL, NULL);
21     avc_init();
22
23     original_ops = secondary_ops = security_ops;
24     if (!secondary_ops)
25         panic ("SELinux: No initial security operations\n");
26     if (register_security (&selinux_ops))
27         panic("SELinux: Unable to register with kernel.\n");
28
29     if (selinux_enforcing) {
30         printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
31     } else {
32         printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
33 }
34
35 #ifdef CONFIG_KEYS
36 /* Add security information to initial keyrings */
37 selinux_key_alloc(&root_user_keyring, current,
38 KEY_ALLOC_NOT_IN_QUOTA);
39 selinux_key_alloc(&root_session_keyring, current,
40 KEY_ALLOC_NOT_IN_QUOTA);
41 #endif
42
43 return 0;
44 }
リスト5 selinux_init関数
  1 static struct security_operations selinux_ops = {
  2     .ptrace =             selinux_ptrace,
  3     .capget =             selinux_capget,
  4     .capset_check =       selinux_capset_check,
  5     .capset_set =         selinux_capset_set,
  6     .sysctl =             selinux_sysctl,
  7     .capable =            selinux_capable,
  8     .quotactl =           selinux_quotactl,
  9     .quota_on =           selinux_quota_on,
 10     .syslog =             selinux_syslog,
 11     .vm_enough_memory =   selinux_vm_enough_memory,

……中略……

170
171 #ifdef CONFIG_KEYS
172     .key_alloc =          selinux_key_alloc,
173     .key_free =           selinux_key_free,
174     .key_permission =     selinux_key_permission,
175 #endif
176 };
リスト6 selinux_ops構造体

フレームワークとしてのLSM

 このようにソースコードを見ると、LSMがフレームワークであることがよくご理解いただけたのではないでしょうか? 次回は、LSMを利用して実際にセキュリティモジュールのサンプルを作成し、その動作を検証してみたいと思います。

2/2

Index
Inside Linux Security Module
 第1回 知られざるセキュリティフレームワーク「LSM」の役割
  Page 1
 SELinuxの背後にいるLSM
 紆余曲折を経て……開発の背景
 LSMが提供する2つの機能
 実はこんなに! LSMを用いたセキュリティモジュール
  Page 2
 ソースコードで見るLSMの動作
 フレームワークとしてのLSM


 Linux Squareフォーラム Linux/システム学習関連記事
連載:Windowsユーザーに教えるLinuxの常識(全12回)
Windowsのセオリーが通用しないLinux。Linux初心者向けに、LinuxというOSの考え方/常識をゼロから伝授!
連載:LFSで作って学ぶLinuxの仕組み(全4回)
管理者(root)は、何をしなければならないのか? 管理に際して検討すべきことは? 管理のための技術とは? など、駆け出し管理者のための考え方や方法論を検討する
連載:Linux管理者への道(全8回)
「Linux From Scratch」というシンプルなLinuxをインストール&環境構築する作業を通して、LinuxがOSとして機能するための仕組みや設定を見直そう
Linux Squareフォーラム全記事インデックス

MONOist組み込み開発フォーラムの中から、Linux関連記事を紹介します


Linux & OSS フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Linux & OSS 記事ランキング

本日 月間