LSM(Linux security module)
1. security_init初始化
内核启动流程:start_kernel()-->security_init()
2. security_init LSM子系统初始化
static struct security_operations *security_ops; //安全操作接口
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(); //执行System.map的代码段,见下面
return 0;
}
3. security_fixup_ops LSM安全操作接口绑定
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);
set_to_cap_if_null(ops, capset);
set_to_cap_if_null(ops, capable);
set_to_cap_if_null(ops, quotactl);
set_to_cap_if_null(ops, quota_on);
set_to_cap_if_null(ops, syslog);
set_to_cap_if_null(ops, settime);
set_to_cap_if_null(ops, vm_enough_memory);
set_to_cap_if_null(ops, bprm_set_creds);
set_to_cap_if_null(ops, bprm_committing_creds);
set_to_cap_if_null(ops, bprm_committed_creds);
set_to_cap_if_null(ops, bprm_check_security);
set_to_cap_if_null(ops, bprm_secureexec);
set_to_cap_if_null(ops, sb_alloc_security);
set_to_cap_if_null(ops, sb_free_security);
set_to_cap_if_null(ops, sb_copy_data);
set_to_cap_if_null(ops, sb_remount);
set_to_cap_if_null(ops, sb_kern_mount);
set_to_cap_if_null(ops, sb_show_options);
set_to_cap_if_null(ops, sb_statfs);
set_to_cap_if_null(ops, sb_mount);
set_to_cap_if_null(ops, sb_umount);
set_to_cap_if_null(ops, sb_pivotroot);
set_to_cap_if_null(ops, sb_set_mnt_opts);
set_to_cap_if_null(ops, sb_clone_mnt_opts);
set_to_cap_if_null(ops, sb_parse_opts_str);
set_to_cap_if_null(ops, inode_alloc_security);
set_to_cap_if_null(ops, inode_free_security);
set_to_cap_if_null(ops, inode_init_security);
set_to_cap_if_null(ops, inode_create);
set_to_cap_if_null(ops, inode_link);
set_to_cap_if_null(ops, inode_unlink);
set_to_cap_if_null(ops, inode_symlink);
set_to_cap_if_null(ops, inode_mkdir);
set_to_cap_if_null(ops, inode_rmdir);
set_to_cap_if_null(ops, inode_mknod);
set_to_cap_if_null(ops, inode_rename);
set_to_cap_if_null(ops, inode_readlink);
set_to_cap_if_null(ops, inode_follow_link);
set_to_cap_if_null(ops, inode_permission);
set_to_cap_if_null(ops, inode_setattr);
set_to_cap_if_null(ops, inode_getattr);
set_to_cap_if_null(ops, inode_setxattr);
set_to_cap_if_null(ops, inode_post_setxattr);
set_to_cap_if_null(ops, inode_getxattr);
set_to_cap_if_null(ops, inode_listxattr);
set_to_cap_if_null(ops, inode_removexattr);
set_to_cap_if_null(ops, inode_need_killpriv);
set_to_cap_if_null(ops, inode_killpriv);
set_to_cap_if_null(ops, inode_getsecurity);
set_to_cap_if_null(ops, inode_setsecurity);
set_to_cap_if_null(ops, inode_listsecurity);
set_to_cap_if_null(ops, inode_getsecid);
#ifdef CONFIG_SECURITY_PATH
set_to_cap_if_null(ops, path_mknod);
set_to_cap_if_null(ops, path_mkdir);
set_to_cap_if_null(ops, path_rmdir);
set_to_cap_if_null(ops, path_unlink);
set_to_cap_if_null(ops, path_symlink);
set_to_cap_if_null(ops, path_link);
set_to_cap_if_null(ops, path_rename);
set_to_cap_if_null(ops, path_truncate);
set_to_cap_if_null(ops, path_chmod);
set_to_cap_if_null(ops, path_chown);
set_to_cap_if_null(ops, path_chroot);
#endif
set_to_cap_if_null(ops, file_permission);
set_to_cap_if_null(ops, file_alloc_security);
set_to_cap_if_null(ops, file_free_security);
set_to_cap_if_null(ops, file_ioctl);
set_to_cap_if_null(ops, mmap_addr);
set_to_cap_if_null(ops, mmap_file);
set_to_cap_if_null(ops, file_mprotect);
set_to_cap_if_null(ops, file_lock);
set_to_cap_if_null(ops, file_fcntl);
set_to_cap_if_null(ops, file_set_fowner);
set_to_cap_if_null(ops, file_send_sigiotask);
set_to_cap_if_null(ops, file_receive);
set_to_cap_if_null(ops, file_open);
set_to_cap_if_null(ops, task_create);
set_to_cap_if_null(ops, task_free);
set_to_cap_if_null(ops, cred_alloc_blank);
set_to_cap_if_null(ops, cred_free);
set_to_cap_if_null(ops, cred_prepare);
set_to_cap_if_null(ops, cred_transfer);
set_to_cap_if_null(ops, kernel_act_as);
set_to_cap_if_null(ops, kernel_create_files_as);
set_to_cap_if_null(ops, kernel_module_request);
set_to_cap_if_null(ops, kernel_module_from_file);
set_to_cap_if_null(ops, task_fix_setuid);
set_to_cap_if_null(ops, task_setpgid);
set_to_cap_if_null(ops, task_getpgid);
set_to_cap_if_null(ops, task_getsid);
set_to_cap_if_null(ops, task_getsecid);
set_to_cap_if_null(ops, task_setnice);
set_to_cap_if_null(ops, task_setioprio);
set_to_cap_if_null(ops, task_getioprio);
set_to_cap_if_null(ops, task_setrlimit);
set_to_cap_if_null(ops, task_setscheduler);
set_to_cap_if_null(ops, task_getscheduler);
set_to_cap_if_null(ops, task_movememory);
set_to_cap_if_null(ops, task_wait);
set_to_cap_if_null(ops, task_kill);
set_to_cap_if_null(ops, task_prctl);
set_to_cap_if_null(ops, task_to_inode);
set_to_cap_if_null(ops, ipc_permission);
set_to_cap_if_null(ops, ipc_getsecid);
set_to_cap_if_null(ops, msg_msg_alloc_security);
set_to_cap_if_null(ops, msg_msg_free_security);
set_to_cap_if_null(ops, msg_queue_alloc_security);
set_to_cap_if_null(ops, msg_queue_free_security);
set_to_cap_if_null(ops, msg_queue_associate);
set_to_cap_if_null(ops, msg_queue_msgctl);
set_to_cap_if_null(ops, msg_queue_msgsnd);
set_to_cap_if_null(ops, msg_queue_msgrcv);
set_to_cap_if_null(ops, shm_alloc_security);
set_to_cap_if_null(ops, shm_free_security);
set_to_cap_if_null(ops, shm_associate);
set_to_cap_if_null(ops, shm_shmctl);
set_to_cap_if_null(ops, shm_shmat);
set_to_cap_if_null(ops, sem_alloc_security);
set_to_cap_if_null(ops, sem_free_security);
set_to_cap_if_null(ops, sem_associate);
set_to_cap_if_null(ops, sem_semctl);
set_to_cap_if_null(ops, sem_semop);
set_to_cap_if_null(ops, netlink_send);
set_to_cap_if_null(ops, d_instantiate);
set_to_cap_if_null(ops, getprocattr);
set_to_cap_if_null(ops, setprocattr);
set_to_cap_if_null(ops, secid_to_secctx);
set_to_cap_if_null(ops, secctx_to_secid);
set_to_cap_if_null(ops, release_secctx);
set_to_cap_if_null(ops, inode_notifysecctx);
set_to_cap_if_null(ops, inode_setsecctx);
set_to_cap_if_null(ops, inode_getsecctx);
#ifdef CONFIG_SECURITY_NETWORK
set_to_cap_if_null(ops, unix_stream_connect);
set_to_cap_if_null(ops, unix_may_send);
set_to_cap_if_null(ops, socket_create); //创建socket
set_to_cap_if_null(ops, socket_post_create);
set_to_cap_if_null(ops, socket_bind);
set_to_cap_if_null(ops, socket_connect);
set_to_cap_if_null(ops, socket_listen);
set_to_cap_if_null(ops, socket_accept);
set_to_cap_if_null(ops, socket_sendmsg);
set_to_cap_if_null(ops, socket_recvmsg);
set_to_cap_if_null(ops, socket_getsockname);
set_to_cap_if_null(ops, socket_getpeername);
set_to_cap_if_null(ops, socket_setsockopt);
set_to_cap_if_null(ops, socket_getsockopt);
set_to_cap_if_null(ops, socket_shutdown);
set_to_cap_if_null(ops, socket_sock_rcv_skb);
set_to_cap_if_null(ops, socket_getpeersec_stream);
set_to_cap_if_null(ops, socket_getpeersec_dgram);
set_to_cap_if_null(ops, sk_alloc_security);
set_to_cap_if_null(ops, sk_free_security);
set_to_cap_if_null(ops, sk_clone_security);
set_to_cap_if_null(ops, sk_getsecid);
set_to_cap_if_null(ops, sock_graft);
set_to_cap_if_null(ops, inet_conn_request);
set_to_cap_if_null(ops, inet_csk_clone);
set_to_cap_if_null(ops, inet_conn_established);
set_to_cap_if_null(ops, secmark_relabel_packet);
set_to_cap_if_null(ops, secmark_refcount_inc);
set_to_cap_if_null(ops, secmark_refcount_dec);
set_to_cap_if_null(ops, req_classify_flow);
set_to_cap_if_null(ops, tun_dev_alloc_security);
set_to_cap_if_null(ops, tun_dev_free_security);
set_to_cap_if_null(ops, tun_dev_create);
set_to_cap_if_null(ops, tun_dev_open);
set_to_cap_if_null(ops, tun_dev_attach_queue);
set_to_cap_if_null(ops, tun_dev_attach);
set_to_cap_if_null(ops, skb_owned_by);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
set_to_cap_if_null(ops, xfrm_policy_alloc_security);
set_to_cap_if_null(ops, xfrm_policy_clone_security);
set_to_cap_if_null(ops, xfrm_policy_free_security);
set_to_cap_if_null(ops, xfrm_policy_delete_security);
set_to_cap_if_null(ops, xfrm_state_alloc_security);
set_to_cap_if_null(ops, xfrm_state_free_security);
set_to_cap_if_null(ops, xfrm_state_delete_security);
set_to_cap_if_null(ops, xfrm_policy_lookup);
set_to_cap_if_null(ops, xfrm_state_pol_flow_match);
set_to_cap_if_null(ops, xfrm_decode_session);
#endif /* CONFIG_SECURITY_NETWORK_XFRM */
#ifdef CONFIG_KEYS
set_to_cap_if_null(ops, key_alloc);
set_to_cap_if_null(ops, key_free);
set_to_cap_if_null(ops, key_permission);
set_to_cap_if_null(ops, key_getsecurity);
#endif /* CONFIG_KEYS */
#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
}
这个函数主要是绑定LSM安全操作接口,这里涉及到结构体,路径:include\linux\security.h
struct security_operations {
char name[SECURITY_NAME_MAX + 1];
int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
int (*ptrace_traceme) (struct task_struct *parent);
int (*capget) (struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted);
int (*capset) (struct cred *new,
const struct cred *old,
const kernel_cap_t *effective,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted);
int (*capable) (const struct cred *cred, struct user_namespace *ns,
int cap, int audit);
int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
int (*quota_on) (struct dentry *dentry);
int (*syslog) (int type);
int (*settime) (const struct timespec *ts, const struct timezone *tz);
int (*vm_enough_memory) (struct mm_struct *mm, long pages);
...
}
4. do_security_initcalls
初始化System.map内部的LSM函数
extern initcall_t __security_initcall_start[], __security_initcall_end[];
static void __init do_security_initcalls(void)
{
initcall_t *call;
call = __security_initcall_start;
while (call < __security_initcall_end) {
(*call) ();
call++;
}
}
在System.map文件内部:
c0442a10 T __security_initcall_end
c0442a10 T __security_initcall_start
这里内部没有函数地址,表明没有启用安全模式。
5. socket套接字 例子
我们通过创建socket套接字来访问LSM
-->应用层创建socket()
-->系统调用
-->SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol),
其中SYSCALL_DEFINE3路径为:include\linux\syscalls.h
-->sock_create(family, type, protocol, &sock)
-->__sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0)
-->security_socket_create(family, type, protocol, kern)
-->security_ops->socket_create(family, type, protocol, kern),该函数将回调如下的接口
在上面第3.内部
set_to_cap_if_null(ops, socket_create);
至此,即可校验socket套接字创建时的domain协议族、socket类型!