無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

セキュアLinuxとは・・・


SELinuxとは、TOMOYO Linuxのような呼称とばかり思っていました。実はTOMOYO LinuxはTOMOYO LinuxでSELinuxはSELinuxと言うことのようです。

ともかく、セキュアなLinuxはLinuxカーネルにセキュリティの機能を付加します。付加する機能はLKMのようにモジュール(LSMと言うそうです。)として提供されるわけですが、LKMのようにinsmod/rmmodする事はできません。カーネル起動時に読み込まれ(これがSEであったりTOMOYOであったりするわけです。)、カーネルの一部として埋め込まれます。従って一度立ち上がったカーネル下で、別のLSMに差し替えたりする事はできません。なおLSMによっては、SELinuxのようにその機能を、無効にする機能をインプリメントしたりしています。

それ故、SELinux/TOMOYO Linuxと称するのも、それぞれのカーネル本体が異なるLinuxと言うことからでないでしょうか?

実装は、security_operationsオブジェクトの静的変数security_opsに、LSMで定義するセキュリティチェックのコールバック関数を設定する事にあります。カーネルでは各処理毎(open等)に、該当するsecurity_opsコールバック関数を呼ぶようになっています。

実装

カーネル起動時のstart_kernel()から、security_init()がコールされ、かかる設定が行われます。security_init()では、デフォルトのsecurity_operationsオブジェクトのdefault_security_opsを、security_opsとする事にあります。
asmlinkage void __init start_kernel(void)
{
 :
 :
       buffer_init();
       key_init();
       security_init();
       dbg_late_init();
       vfs_caches_init(totalram_pages);
  :
  :
}
default_security_opsでのコールバックは何も定義されていません。security_fixup_ops()で、定義されていないコールバック関数を、cap_##function名のコールバック関数として、カーネル内のデフォルト関数がコールされるように設定し、それをsecurity_ops = &default_security_opsとしています。

do_security_initcalls()は、アドレスの__security_initcall_startから__security_initcall_endまでの、初期化処理がコールされるようです。たぶんこの時、指定されるLSMが読み込まれ、そのLSM名等が設定されたりするのでないでしょうか・・・。
static struct security_operations default_security_ops = {
       .name   = "default",
};

int __init security_init(void)
{
       printk(KERN_INFO "Security Framework initialized\n");

       security_fixup_ops(&default_security_ops);
       security_ops = &default_security_ops;
       do_security_initcalls();

       return 0;
}

void __init security_fixup_ops(struct security_operations *ops)
{
       set_to_cap_if_null(ops, ptrace_access_check);
       set_to_cap_if_null(ops, ptrace_traceme);
       set_to_cap_if_null(ops, capget);
  :
  :
#ifdef CONFIG_AUDIT
       set_to_cap_if_null(ops, audit_rule_init);
       set_to_cap_if_null(ops, audit_rule_known);
       set_to_cap_if_null(ops, audit_rule_match);
       set_to_cap_if_null(ops, audit_rule_free);
#endif
}

#define set_to_cap_if_null(ops, function)                               \
       do {                                                            \
               if (!ops->function) {                                   \
                       ops->function = cap_##function;                 \
                       pr_debug("Had to override the " #function       \
                                " security operation with the default.\n");\
                       }                                               \
       } while (0)
TOMOYO Linuxは、以下の様になっています。
static struct security_operations tomoyo_security_ops = {
       .name                = "tomoyo",
       .cred_alloc_blank    = tomoyo_cred_alloc_blank,
       .cred_prepare        = tomoyo_cred_prepare,
       .cred_transfer       = tomoyo_cred_transfer,
       .cred_free           = tomoyo_cred_free,
       .bprm_set_creds      = tomoyo_bprm_set_creds,
       .bprm_check_security = tomoyo_bprm_check_security,
       .file_fcntl          = tomoyo_file_fcntl,
       .dentry_open         = tomoyo_dentry_open,
       .path_truncate       = tomoyo_path_truncate,
       .path_unlink         = tomoyo_path_unlink,
       .path_mkdir          = tomoyo_path_mkdir,
       .path_rmdir          = tomoyo_path_rmdir,
       .path_symlink        = tomoyo_path_symlink,
       .path_mknod          = tomoyo_path_mknod,
       .path_link           = tomoyo_path_link,
       .path_rename         = tomoyo_path_rename,
       .inode_getattr       = tomoyo_inode_getattr,
       .file_ioctl          = tomoyo_file_ioctl,
       .path_chmod          = tomoyo_path_chmod,
       .path_chown          = tomoyo_path_chown,
       .path_chroot         = tomoyo_path_chroot,
       .sb_mount            = tomoyo_sb_mount,
       .sb_umount           = tomoyo_sb_umount,
       .sb_pivotroot        = tomoyo_sb_pivotroot,
       .socket_bind         = tomoyo_socket_bind,
       .socket_connect      = tomoyo_socket_connect,
       .socket_listen       = tomoyo_socket_listen,
       .socket_sendmsg      = tomoyo_socket_sendmsg,
};

static int __init tomoyo_init(void)
{
       struct cred *cred = (struct cred *) current_cred();

       if (!security_module_enable(&tomoyo_security_ops))
               return 0;
       if (register_security(&tomoyo_security_ops) ||
           init_srcu_struct(&tomoyo_ss))
               panic("Failure registering TOMOYO Linux");
       printk(KERN_INFO "TOMOYO Linux initialized\n");
       cred->security = &tomoyo_kernel_domain;
       tomoyo_mm_init();
       return 0;
}

int __init security_module_enable(struct security_operations *ops)
{
       return !strcmp(ops->name, chosen_lsm);
}

int __init register_security(struct security_operations *ops)
{
       if (verify(ops)) {
               printk(KERN_DEBUG "%s could not verify "
                      "security_operations structure.\n", __func__);
               return -EINVAL;
       }

       if (security_ops != &default_security_ops)
               return -EAGAIN;

       security_ops = ops;

       return 0;
}
ちなみにファイルオープン時で、パーミッションチェックでinode_permission()がコールされます。ファイルモードにかかるチェックをした後、security_inode_permission()から、security_ops->inode_permissionコールバックをコールして、セキュアチェックをしています。
int inode_permission(struct inode *inode, int mask)
{
       int retval;

       if (unlikely(mask & MAY_WRITE)) {
               umode_t mode = inode->i_mode;

               if (IS_RDONLY(inode) &&
                   (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
                       return -EROFS;

               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);
}

int security_inode_permission(struct inode *inode, int mask)
{
       if (unlikely(IS_PRIVATE(inode)))
               return 0;
       return security_ops->inode_permission(inode, mask);
}

補足

セキュアLinuxは使った事がありませんし、TOMOYO LinuxはSELinuxの1つだとばっかり思っていた程のレベルで、具体的に理解しておらず、上っ面をさっと舐めただけです。従って嘘もあるかと思います・・・。


最終更新 2012/11/09 18:15:36 - north
(2012/11/09 18:15:36 作成)