儿子第一次眼泛泪光


都说要去到星辰大海,但是他们不知道,你也是宇宙的孩子与星辰大海没什么两样

今天早餐的时候,儿子调皮想吃我碗里的东西,趴在桌子上够着够着“啪”碗给打翻了,碗里都是热汤,第一反应是确定有没有受伤,第二反应是生气。我板着脸盯着他看了几秒,然后问他“有没有受伤?,知不知道这样做很危险?”,再后来说了什么有点忘记了,大多是叮嘱的话只是都很严肃。现在回忆起来,我唯一记得的就是感受到儿子有点愣住的时候,我心软了,我轻轻地把他从凳子上抱下来,等他站稳之后我跟他四目相对的一瞬间,我看到了泪光——一个一岁半的孩子眼泛泪光。我不确定是做错事的悔意,还是因为父亲的面露严肃而不知所措。顿时间我有点慌乱,心疼和不知所措在我的心里翻江倒海。
现在回忆起这个细节,还是有点揪心。我相信对于儿子来讲这是一件他不会记挂在心里很久的事情,但是我还是希望更好的避免这样的问题。我的出发点有几个:
* 希望他开心,一个人奔奔跳跳踢腿甩胳膊的场景我相信他是最快乐的
* 希望他健康(身心皆是),父母亲人的情绪和交流的方式对孩子的养成有至关重要的影响
* 希望他成人,抛开生物学和心理学我还是认为人之所以区别于兽在于其具备“仁义礼智信”

我揪心和不知所措源自于我因为他懵懂的行为让他变得不开心,甚至还有可能伤害他的身心健康,同时我这么做还不一定能帮助他成人。这也是我第一次产生了作为父亲的迷茫,我坚信健康、成人一定有一条开心的路,或者说看上去不需要“眼泛泪光”的路。
最近几个月我发现儿子的成长和变化很快,反观我自己目前关于育儿的书籍我只读完了3本,讲座、咨询之类也少有参加,这也就意味着我的成长已经落伍于儿子的成长,对此我感到非常的惭愧和悔恨。我相信这里面有科学的方法来帮助我解决今天碰到的问题,只是我还没有完成学习。
史铁生在《病隙碎笔》里的一段话:“你不必非得看过多少本书,但你要看中这沉默,这黑夜,它教会你思想而不单是看书。你可以多看些书,但世上的书从未被哪一个人看完过,而看过很多书却没有思想能力的人却也不少。”。所以跟儿子的相处不应该仅仅是看书、讲座、上课,我相信一个会“Give Me Five”的父亲再怎么严肃,他的孩子也不会不爱他。期待我跟儿子的成长……

Linux Kernel LSM Hook Technology


说明:本文源码涉及的Kernel版本是5.10

1. 背景

2001年之前就有很多安全访问控制模型和框架已经被研究和开发出来,用以增强Linux系统的安全性,例如SELinux,DTE,LIDS等等。这些模型和框架大多以各种不同的内核补丁的形式提供,但是没有一个能够获得统治性的地位进而成为Linux内核标准,使用这些系统需要有编译和定制内核的能力,对于没有内核开发经验的普通用户,获得并使用这些系统是有难度的。在2001年的Linux内核峰会上,美国国家安全局(NSA)介绍了他们关于安全增强Linux(SELinux)的工作,当时Linux内核的创始人Linus Torvalds同意Linux内核确实需要一个通用的安全访问控制框架,但他指出最好是通过可加载内核模块的方法,这样可以支持现存的各种不同的安全访问控制系统。因此Linux安全模块(LSM)应运而生。

LSM是在kernel编译的时候通过配置CONFIG_DEFAULT_SECURITY进行选择的built-in kernel里面,当系统中有多个LSM的时候可以通过kernel命令行security=进行配置。

2. LSM框架

Linus Torvalds对Linux安全模块(LSM)提出了三点要求:

  • 真正的通用,当使用一个不同的安全模型的时候,只需要加载一个不同的内核模块
  • 概念上简单,对Linux内核影响最小,高效
  • 能够支持现存的POSIX.1e capabilities逻辑,作为一个可选的安全模块

2.1 设计目标

  1. 以可加载内核模块的形式实现,不会在安全性方面带来明显的损失也不会带来额外的系统开销
  2. 为了满足大多数现存Linux安全增强系统的需要,采取简化设计的决策减少了对Linux内核的修改和影响

为了满足这些设计目标,Linux安全模块(LSM)采用了通过在内核源代码中放置钩子的方法,来决策是否可以对内核内部对象进行的访问,这些对象有:任务,inode结点,打开的文件等等。LSM访问内核态对象的大致流程如下图所示:

2.2 LSM工作原理

为了更加容易理解LSM的工作原理,现在以Linux打开文件int open(const char *pathname, int flags, mode_t mode);为例来观察kernel中的LSM模块是如何工作。假设用户态进程调用open接口想要打开某个路径下面的文件,那么会有如下的大致流程:

  1. 用户态进程调用以文件路径filepath为入参调用open接口
  2. open系统调用在內核态得到调度,filepath字符串用来帮助找到kernel file object
  3. kernel DAC模块校验文件权限(即用户态进程是否有文件的open权限)
  4. kernel LSM框架依次调用所有激活的LSM模块的file_open相关的勾子函数,只要有一个勾子函数返回错误则中断该系统调用
  5. 所有安全检查通过之后,进程打开文件并返回文件描述符给用户态

2.3 勾子函数

目前kernel LSM(version 5.10)框架总共包括了224个勾子点。简单说明一下比较常见的勾子点:

1. Task Hooks
LSM provides a set of task hooks that enable security modules to manage process security information and to control process operations

2. Program Loading Hooks
LSM provides a set of programloading hooks that are called at critical points during the processing of an execve operation."linux_binprm"

3. IPC Hooks
Security modules can manage security information and perform access control for System V IPC using the LSM IPC hooks.
LSM inserts a hook into the existing ipcperms function so that a security module can perform a check for each existing Linux IPC permission check 

4. Filesystem Hooks
For file operations, three sets of hooks were defined:
    1) filesystem hooks
    2) inode hooks
    3) file hooks

5. Network Hooks
Application layer access to networking is mediated using a set of socket hooks. These hooks, which include interposition of all socket system calls, provide coarse mediation coverage of all socket-based protocols.
Since active user sockets have an associated inode structure, a separate security field was not added to the socket structure or to the lower-level sock structure.
As the socket hooks allow general mediation of network traffic in relation to processes, LSM significantly expands the kernel’s network access control framework (which is already handled at the network layer by Netfilter)(LSM对网络的访问控制和Netfilter保持兼容). 
For example, the sock rcv skb hook allows an inbound packet to be mediated in terms of its destination application, prior to being queued at the associated userspace socket.

6. Other Hooks
LSM provides two additional sets of hooks: 
    1) module hooks
    Module hooks can be used to control the kernel operations that create, initialize, and delete kernel modules.

    2) a set of top-level system hooks
    System hooks can be used to control system operations, such as setting the system hostname, accessing I/O ports, and configuring process accounting.

3. LSM源码分析

3.1. LSM初始化

/**
 * security_init - initializes the security framework
 *
 * This should be called early in the kernel initialization sequence.
 */
int __init security_init(void)
{
    int i;
    struct hlist_head *list = (struct hlist_head *) &security_hook_heads;

    pr_info("Security Framework initializing\n");

    /* 初始化hook list用来保存hook点 */
    for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head);
         i  )
        INIT_HLIST_HEAD(&list[i]);

    /**
     * LSM分为major和minor两种,major具备排他性(SELinux,AppArmor,TOMOYO),
     * major LSM都是一种MAC实现,所以通过用户态配置来加载。LSM实现的排他性通过
     * LSM_FLAG_EXCLUSIVE控制。
     */
    /*
     * Load minor LSMs, with the capability module always first.
     */
    capability_add_hooks();
    yama_add_hooks();
    loadpin_add_hooks();

    /* 根据cmdline和builtin配置参数加载具体的LSM模块,例如SELinux */
    /* Load LSMs in specified order. */
    ordered_lsm_init();

    return 0;
}

/* Initialize a given LSM, if it is enabled. */
static void __init initialize_lsm(struct lsm_info *lsm)
{
    if (is_enabled(lsm)) {
        int ret;

        init_debug("initializing %s\n", lsm->name);
        ret = lsm->init();
        WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
    }
}

3.2. LSM模块(以SELinux模块为例)

/* ------------------------------------------------------------- */
/* 以SELinux模块为例看LSM的初始化 */
/* SELinux requires early initialization in order to label
   all processes and objects when they are created. */
DEFINE_LSM(selinux) = {
    .name = "selinux",
    .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
    .enabled = &selinux_enabled,
    .init = selinux_init,
};
static __init int selinux_init(void)
{
    pr_info("SELinux:  Initializing.\n");

    memset(&selinux_state, 0, sizeof(selinux_state));
    enforcing_set(&selinux_state, selinux_enforcing_boot);
    selinux_state.checkreqprot = selinux_checkreqprot_boot;
    selinux_ss_init(&selinux_state.ss);
    selinux_avc_init(&selinux_state.avc);

    /* Set the security state for the initial task. */
    cred_init_security();

    default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);

    sel_inode_cache = kmem_cache_create("selinux_inode_security",
                        sizeof(struct inode_security_struct),
                        0, SLAB_PANIC, NULL);
    file_security_cache = kmem_cache_create("selinux_file_security",
                        sizeof(struct file_security_struct),
                        0, SLAB_PANIC, NULL);
    avc_init();

    avtab_cache_init();

    ebitmap_cache_init();

    hashtab_cache_init();

    /* 增加SELinux的勾子点 */
    security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");

    if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
        panic("SELinux: Unable to register AVC netcache callback\n");

    if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET))
        panic("SELinux: Unable to register AVC LSM notifier callback\n");

    if (selinux_enforcing_boot)
        pr_debug("SELinux:  Starting in enforcing mode\n");
    else
        pr_debug("SELinux:  Starting in permissive mode\n");

    return 0;
}
/* SELinux 定义的勾子链表 */
static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
    LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
    LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
    LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
    LSM_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file),

    LSM_HOOK_INIT(ptrace_access_check, selinux_ptrace_access_check),
    LSM_HOOK_INIT(ptrace_traceme, selinux_ptrace_traceme),
    LSM_HOOK_INIT(capget, selinux_capget),
    LSM_HOOK_INIT(capset, selinux_capset),
    LSM_HOOK_INIT(capable, selinux_capable),
    LSM_HOOK_INIT(quotactl, selinux_quotactl),
    LSM_HOOK_INIT(quota_on, selinux_quota_on),
    LSM_HOOK_INIT(syslog, selinux_syslog),
    LSM_HOOK_INIT(vm_enough_memory, selinux_vm_enough_memory),

    LSM_HOOK_INIT(netlink_send, selinux_netlink_send),

    LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds),
    LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
    LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),

    LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
    LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
    LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),
    LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
    LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
    LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
    LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs),
    LSM_HOOK_INIT(sb_mount, selinux_mount),
    LSM_HOOK_INIT(sb_umount, selinux_umount),
    LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts),
    LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts),
    LSM_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str),

    LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security),
    LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as),

    LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
    LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security),
    LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security),
    LSM_HOOK_INIT(inode_create, selinux_inode_create),
    LSM_HOOK_INIT(inode_link, selinux_inode_link),
    LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink),
    LSM_HOOK_INIT(inode_symlink, selinux_inode_symlink),
    LSM_HOOK_INIT(inode_mkdir, selinux_inode_mkdir),
    LSM_HOOK_INIT(inode_rmdir, selinux_inode_rmdir),
    LSM_HOOK_INIT(inode_mknod, selinux_inode_mknod),
    LSM_HOOK_INIT(inode_rename, selinux_inode_rename),
    LSM_HOOK_INIT(inode_readlink, selinux_inode_readlink),
    LSM_HOOK_INIT(inode_follow_link, selinux_inode_follow_link),
    LSM_HOOK_INIT(inode_permission, selinux_inode_permission),
    LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr),
    LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr),
    LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr),
    LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr),
    LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
    LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr),
    LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr),
    LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
    LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
    LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
    LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
    LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
    LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),

    LSM_HOOK_INIT(file_permission, selinux_file_permission),
    LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
    LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
    LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
    LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
    LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
    LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
    LSM_HOOK_INIT(file_lock, selinux_file_lock),
    LSM_HOOK_INIT(file_fcntl, selinux_file_fcntl),
    LSM_HOOK_INIT(file_set_fowner, selinux_file_set_fowner),
    LSM_HOOK_INIT(file_send_sigiotask, selinux_file_send_sigiotask),
    LSM_HOOK_INIT(file_receive, selinux_file_receive),

    /**
     * 在LSM框架管理的勾子链表中增加file_open,其中勾子函数为
     * selinux_file_open,即:
     * file_open = head_list{
     *   .head=security_hook_heads,
     *   .hook=head_list{
     *       .head=selinux_file_open,
     *   }
     * };
     */
    LSM_HOOK_INIT(file_open, selinux_file_open),

    LSM_HOOK_INIT(task_alloc, selinux_task_alloc),
    LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank),
    LSM_HOOK_INIT(cred_free, selinux_cred_free),
    LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
    LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
    LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
    LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
    LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
    LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
    LSM_HOOK_INIT(kernel_load_data, selinux_kernel_load_data),
    LSM_HOOK_INIT(kernel_read_file, selinux_kernel_read_file),
    LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
    LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
    LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
    LSM_HOOK_INIT(task_getsecid, selinux_task_getsecid),
    LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
    LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
    LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
    LSM_HOOK_INIT(task_prlimit, selinux_task_prlimit),
    LSM_HOOK_INIT(task_setrlimit, selinux_task_setrlimit),
    LSM_HOOK_INIT(task_setscheduler, selinux_task_setscheduler),
    LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler),
    LSM_HOOK_INIT(task_movememory, selinux_task_movememory),
    LSM_HOOK_INIT(task_kill, selinux_task_kill),
    LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode),

    LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
    LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),

    LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security),
    LSM_HOOK_INIT(msg_msg_free_security, selinux_msg_msg_free_security),

    LSM_HOOK_INIT(msg_queue_alloc_security,
            selinux_msg_queue_alloc_security),
    LSM_HOOK_INIT(msg_queue_free_security, selinux_msg_queue_free_security),
    LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
    LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
    LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd),
    LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv),

    LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
    LSM_HOOK_INIT(shm_free_security, selinux_shm_free_security),
    LSM_HOOK_INIT(shm_associate, selinux_shm_associate),
    LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl),
    LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat),

    LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
    LSM_HOOK_INIT(sem_free_security, selinux_sem_free_security),
    LSM_HOOK_INIT(sem_associate, selinux_sem_associate),
    LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl),
    LSM_HOOK_INIT(sem_semop, selinux_sem_semop),

    LSM_HOOK_INIT(d_instantiate, selinux_d_instantiate),

    LSM_HOOK_INIT(getprocattr, selinux_getprocattr),
    LSM_HOOK_INIT(setprocattr, selinux_setprocattr),

    LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
    LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
    LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
    LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
    LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
    LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
    LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
    LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),

    LSM_HOOK_INIT(unix_stream_connect, selinux_socket_unix_stream_connect),
    LSM_HOOK_INIT(unix_may_send, selinux_socket_unix_may_send),

    LSM_HOOK_INIT(socket_create, selinux_socket_create),
    LSM_HOOK_INIT(socket_post_create, selinux_socket_post_create),
    LSM_HOOK_INIT(socket_socketpair, selinux_socket_socketpair),
    LSM_HOOK_INIT(socket_bind, selinux_socket_bind),
    LSM_HOOK_INIT(socket_connect, selinux_socket_connect),
    LSM_HOOK_INIT(socket_listen, selinux_socket_listen),
    LSM_HOOK_INIT(socket_accept, selinux_socket_accept),
    LSM_HOOK_INIT(socket_sendmsg, selinux_socket_sendmsg),
    LSM_HOOK_INIT(socket_recvmsg, selinux_socket_recvmsg),
    LSM_HOOK_INIT(socket_getsockname, selinux_socket_getsockname),
    LSM_HOOK_INIT(socket_getpeername, selinux_socket_getpeername),
    LSM_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt),
    LSM_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt),
    LSM_HOOK_INIT(socket_shutdown, selinux_socket_shutdown),
    LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb),
    LSM_HOOK_INIT(socket_getpeersec_stream,
            selinux_socket_getpeersec_stream),
    LSM_HOOK_INIT(socket_getpeersec_dgram, selinux_socket_getpeersec_dgram),
    LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
    LSM_HOOK_INIT(sk_free_security, selinux_sk_free_security),
    LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security),
    LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid),
    LSM_HOOK_INIT(sock_graft, selinux_sock_graft),
    LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request),
    LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
    LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
    LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
    LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
    LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
    LSM_HOOK_INIT(secmark_relabel_packet, selinux_secmark_relabel_packet),
    LSM_HOOK_INIT(secmark_refcount_inc, selinux_secmark_refcount_inc),
    LSM_HOOK_INIT(secmark_refcount_dec, selinux_secmark_refcount_dec),
    LSM_HOOK_INIT(req_classify_flow, selinux_req_classify_flow),
    LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),
    LSM_HOOK_INIT(tun_dev_free_security, selinux_tun_dev_free_security),
    LSM_HOOK_INIT(tun_dev_create, selinux_tun_dev_create),
    LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue),
    LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach),
    LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open),
#ifdef CONFIG_SECURITY_INFINIBAND
    LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access),
    LSM_HOOK_INIT(ib_endport_manage_subnet,
              selinux_ib_endport_manage_subnet),
    LSM_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security),
    LSM_HOOK_INIT(ib_free_security, selinux_ib_free_security),
#endif
#ifdef CONFIG_SECURITY_NETWORK_XFRM
    LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc),
    LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone),
    LSM_HOOK_INIT(xfrm_policy_free_security, selinux_xfrm_policy_free),
    LSM_HOOK_INIT(xfrm_policy_delete_security, selinux_xfrm_policy_delete),
    LSM_HOOK_INIT(xfrm_state_alloc, selinux_xfrm_state_alloc),
    LSM_HOOK_INIT(xfrm_state_alloc_acquire,
            selinux_xfrm_state_alloc_acquire),
    LSM_HOOK_INIT(xfrm_state_free_security, selinux_xfrm_state_free),
    LSM_HOOK_INIT(xfrm_state_delete_security, selinux_xfrm_state_delete),
    LSM_HOOK_INIT(xfrm_policy_lookup, selinux_xfrm_policy_lookup),
    LSM_HOOK_INIT(xfrm_state_pol_flow_match,
            selinux_xfrm_state_pol_flow_match),
    LSM_HOOK_INIT(xfrm_decode_session, selinux_xfrm_decode_session),
#endif

#ifdef CONFIG_KEYS
    LSM_HOOK_INIT(key_alloc, selinux_key_alloc),
    LSM_HOOK_INIT(key_free, selinux_key_free),
    LSM_HOOK_INIT(key_permission, selinux_key_permission),
    LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
#endif

#ifdef CONFIG_AUDIT
    LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init),
    LSM_HOOK_INIT(audit_rule_known, selinux_audit_rule_known),
    LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
    LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
#endif

#ifdef CONFIG_BPF_SYSCALL
    LSM_HOOK_INIT(bpf, selinux_bpf),
    LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
    LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
    LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
    LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
    LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
    LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
#endif
};

3.3. LSM模块生效(以SELinux和open为例)

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
    return ksys_open(filename, flags, mode);
}

static inline long ksys_open(const char __user *filename, int flags,
                 umode_t mode)
{
    if (force_o_largefile())
        flags |= O_LARGEFILE;
    return do_sys_open(AT_FDCWD, filename, flags, mode);
}

long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
    struct open_how how = build_open_how(flags, mode);
    return do_sys_openat2(dfd, filename, &how);
}

...

struct file *do_filp_open(int dfd, struct filename *pathname,
        const struct open_flags *op);

static struct file *path_openat(struct nameidata *nd,
            const struct open_flags *op, unsigned flags);
            
static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file);

int vfs_open(const struct path *path, struct file *file);
...

int vfs_open(const struct path *path, struct file *file)
{
    file->f_path = *path;
    return do_dentry_open(file, d_backing_inode(path->dentry), NULL);
}
static int do_dentry_open(struct file *f,
              struct inode *inode,
              int (*open)(struct inode *, struct file *))
{
    ...
    
    error = security_file_open(f);
    if (error)
        goto cleanup_all;

cleanup_all:
    if (WARN_ON_ONCE(error > 0))
        error = -EINVAL;
    fops_put(f->f_op);
    if (f->f_mode & FMODE_WRITER) {
        put_write_access(inode);
        __mnt_drop_write(f->f_path.mnt);
    }
cleanup_file:
    path_put(&f->f_path);
    f->f_path.mnt = NULL;
    f->f_path.dentry = NULL;
    f->f_inode = NULL;
    return error;
}
int security_file_open(struct file *file)
{
    int ret;

    ret = call_int_hook(file_open, 0, file);
    if (ret)
        return ret;

    return fsnotify_perm(file, MAY_OPEN);
}
#define call_int_hook(FUNC, IRC, ...) ({            \
    int RC = IRC;                       \
    do {                            \
        struct security_hook_list *P;           \
                                \
        hlist_for_each_entry(P, &security_hook_heads.FUNC, list) { \
            RC = P->hook.FUNC(__VA_ARGS__);     \
            if (RC != 0)                \
                break;              \
        }                       \
    } while (0);                        \
    RC;                         \
})
static int selinux_file_open(struct file *file)
{
    struct file_security_struct *fsec;
    struct inode_security_struct *isec;

    fsec = file->f_security;
    isec = inode_security(file_inode(file));
    /*
     * Save inode label and policy sequence number
     * at open-time so that selinux_file_permission
     * can determine whether revalidation is necessary.
     * Task label is already saved in the file security
     * struct as its SID.
     */
    fsec->isid = isec->sid;
    fsec->pseqno = avc_policy_seqno(&selinux_state);
    /*
     * Since the inode label or policy seqno may have changed
     * between the selinux_inode_permission check and the saving
     * of state above, recheck that access is still permitted.
     * Otherwise, access might never be revalidated against the
     * new inode label or new policy.
     * This check is not redundant - do not remove.
     */
    return file_path_has_perm(file->f_cred, file, open_file_to_av(file));
}

4 KRSI LSM模块源码分析

TODO

5 LSM模块编程

实现一个获取当前执行进程的绝对路径的LSM模块,代码如下:

test_lsm_module.c

#include <linux/security.h>
#include <linux/sysctl.h>
#include <linux/ptrace.h>
#include <linux/prctl.h>
#include <linux/ratelimit.h>
#include <linux/workqueue.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/dcache.h>
#include <linux/path.h>
#include <linux/kprobes.h>
#include <linux/module.h> 

static int (*register_security_p)(struct security_operations *ops);
static int (*unregister_security_p)(struct security_operations * ops);

// do nothing
int kprobe_pre(struct kprobe *p, struct pt_regs *regs)
{
        return 0;
}

static void* acquire_func_by_kprobe(char* func_name)
{
    void *symbol_addr=NULL;
    struct kprobe kp;

    do
    {
       memset(&kp, 0, sizeof(kp));
       kp.symbol_name = func_name;
       kp.pre_handler = kprobe_pre;
       if(register_kprobe(&kp) != 0)
       {
            symbol_addr=(void*)kp.addr;
            break;
       }
       //this is the address of  "symbol_name"
       symbol_addr = (void*)kp.addr;

       //now kprobe is not used any more,so unregister it
       unregister_kprobe(&kp);

    }while(false);

    return symbol_addr;
}

int execve_lsm_hook(struct linux_binprm *bprm)
{
    struct cred *currentCred;

    if (bprm->filename)
    {
        printk("file: %s\n", bprm->filename);
        //printk("file argument: %s\n",bprm->p);
    }
    else
    {
        printk("file exec\n");
    } 
    
    currentCred = current->cred;    
    printk(KERN_INFO "uid = %d\n", currentCred->uid);
    printk(KERN_INFO "gid = %d\n", currentCred->gid);
    printk(KERN_INFO "suid = %d\n", currentCred->suid);
    printk(KERN_INFO "sgid = %d\n", currentCred->sgid);
    printk(KERN_INFO "euid = %d\n", currentCred->euid);
    printk(KERN_INFO "egid = %d\n", currentCred->egid);  

    printk("comm: %s\n", current->comm);

    return 0;
} 

static struct security_operations test_security_ops = 
{
        .name = "test",
        .bprm_check_security = execve_lsm_hook,
};

static __init int test_init(void)
{
    int ret_val = -1;

    //获取register_security的导出地址
    register_security_p = acquire_func_by_kprobe("register_security");
    printk("register_security:%p\n", register_security_p);   
    if (!register_security_p)
    {
        printk("get register_security error\n");
    }  

    //获取unregister_security的导出地址
    unregister_security_p = acquire_func_by_kprobe("unregister_security");
    printk("unregister_security:%p\n", unregister_security_p);
    if (!unregister_security_p)
    {
        printk("get unregister_security error\n"); 
    }
     
    //注册LSMsbas
     //if (register_security_p && unregister_security_p)
     if (register_security_p)
    {
        ret_val = register_security_p(&test_security_ops); 
        printk("register_security:%d\n", ret_val);  
    }  

       return 0;
} 

static void test_cleanup(void)
{
    int ret_val=-1;

    //if (register_security_p && unregister_security_p)
    if (unregister_security_p)
    {
        ret_val = register_security_p(&test_security_ops); 
        printk("register_security:%d\n", ret_val);  
    }

    return;
} 

module_init(test_init);
module_exit(test_cleanup);

//一定要有这个声明,否则会有unknown module symbol error
MODULE_LICENSE("GPL");

Makefile

obj-m := execve_lsm_hook.o
PWD       := $(shell pwd)

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    rm -rf *.o *~ core .*.cmd *.mod.c ./tmp_version *.ko modules.order  Module.symvers

clean_omit:
    rm -rf *.o *~ core .*.cmd *.mod.c ./tmp_version modules.order  Module.symvers

随记_2021-05-18


随记_2021–05–18

饭后畅想退休生活,感觉开个咖啡馆挺不错的,像这样的:

下班路上看到了一个酒吧,感觉开一个也挺不错的,像这样:

然后倒一杯咖啡或者精酿一坐一天,为什么能坐一天呢?一来不差钱,一来年纪大了,毕竟上了年纪的人目之所及皆是回忆,心之所想皆是过往;眼之所看皆是遗憾,耳之所闻皆是呢喃!轻呷一口,厚重的嗓音随后响起:

“辛丑年,钱塘江”

“互联网江湖”

“乱”

“很乱”

“非常乱”

……

有点古龙的味道,也有点期待退休的日子,按照国家规定算来算去我还有40+年才能这么做,哎~~

随记_2021-04-05


清明假期最后一天陪家人来了一次清明一日游,早起给儿子去法喜寺求福,然后去老头儿吃了午饭,吃完以后去城市阳台转了转,回家小憩一会之后带着儿子去游泳课。用老婆的话来说“痛并快乐的一天”,晚上虽然累,还是想把这一天零零碎碎的想法记录下来。

  • 原来法喜寺又叫做法喜讲寺,也叫上天竺,在越国就有了
  • 今天看到了法喜寺有一个很大的牌匾,大概的意思是宗教山之首,我感慨了一下,貌似有点冒犯神明
  • 今天在法喜寺参拜的时候,虽然去之初是有目的的,但是当我闭上眼睛参拜的时候,一时间忘记自己应该怎么跟佛祖对话表达自己的愿望,不知道是心诚还是不诚。参拜的时候在想佛祖的存在虚无缥缈,众生所求是什么呢?心安、名利、抑或是寄托,我愿意相信有佛祖这样的存在,只是芸芸众生之一的我大概率是不会遇到这样的存在,所以我所求是什么?在参拜的时候,我在想应该会有拖着病体前来祈求的人,可是病痛真的会少吗?或者心理觉得好过一点,其实并没有真正的变好
  • 城市阳台的游玩充分释放了儿子的活力,难得的亲子时间,家人脸上散开的笑容让我感受到了家的温馨,脑海中突然冒出了一段话”个人性格和经历造成了我自身存在的一些问题,不善沟通、敏感偏执,但是幸运的是家人让我学会了爱和被爱“
  • 剩下的,好像老婆对自己的身材有非常大的不满,我打算找找减肥计划打印出俩给她,她很懒估计肯定不会去打印一个什么减肥计划,至于减肥计划的坚持实施只能留到后面再想办法

P.S. 我很好奇为什么老婆的膀胱如此强大,在外面玩的时候我去洗手间的频率比她高得多,难道是肾虚。。。

谈谈最近看到的一本书


最近看了一本书,我觉得是一本很神奇的书,书名《鹅鹅鹅》,作者叫二冬。这本书大概是长下面这样的:

刚开始读这本书的时候,有点平淡如水的感觉,就好像刚吃了一顿美味的“麻辣烫”之后再喝粥,这其中味道的寡淡不言而喻。由于是通勤的时候随手拿起来的,没有很强的目的性来读这本书,不知不觉也就这么看下去了,就像喝水一样就这么喝着喝着。两天之后回过头来看发现自己随着作者带入到他书中描述的生活中了,大鹅、摩托车、蜱虫、狗、山。没有大道理,有一些生活感悟也是蜻蜓点水般带过。之所以说这本书神奇恰恰就是这里,我居然就这么沉浸其中了,愿意看读下去不觉得乏味,细细想来应该是这本书的字里行间充斥生活气息,少了微信、头条这类媒体上泛滥的焦虑感。

我开始对作者很好奇,不过还没有时间去对作者做一些了解,不过我敢肯定,他的文风是我喜欢的,如果我坚持写作的话,我希望自己也可以这样。