セキュア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); }