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类型!