セキュア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コールバック関数を呼ぶようになっています。
do_security_initcalls()は、アドレスの__security_initcall_startから__security_initcall_endまでの、初期化処理がコールされるようです。たぶんこの時、指定されるLSMが読み込まれ、そのLSM名等が設定されたりするのでないでしょうか・・・。
ともかく、セキュアな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);
}





