You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux安全模块:共享库加载校验与路径、魔数读取异常排查

问题解答

1. 路径获取失败与魔数读取错误的原因及解决方法

1.1 路径显示(efault)的原因

  • 文件对象在file_open钩子触发时可能未完成完整初始化,f_path的路径解析依赖VFS的挂载点、符号链接遍历,此时直接读取可能无法得到有效路径。
  • 直接使用dentry->d_name.name仅能获取文件名,无法得到完整路径;自定义的xattracl_get_realpath若未正确处理内核路径解析的资源管理(如path_get()/path_put()),也会导致路径获取失败。

1.2 魔数读取随机错误的原因

  • 代码存在语法错误:kernel_read(file,value,4,0)==-1);多了一个右括号,且未检查实际读取的字节数是否为4,读取失败时仍会使用未初始化的value,导致垃圾数据。
  • file_open触发时,文件的文件指针位置未初始化,kernel_read使用偏移0不一定能正确读取部分文件系统或特殊打开模式下的文件。
  • 未检查文件的可读权限:struct file的f_mode可能没有FMODE_READ,直接读取会返回无效数据。
  • 调用filp_open会递归触发自身的file_open钩子,导致栈溢出panic。

1.3 正确获取魔数的方法

无需重新打开文件,直接通过inode读取文件第一个块的内容(内核态安全操作):

#include <linux/fs.h>
#include <linux/buffer_head.h>

int xattracl_file_magic_check_elf(struct file *file) {
    struct inode *inode = file_inode(file);
    struct buffer_head *bh;
    int iself = 0;

    // 仅处理普通文件
    if (!S_ISREG(inode->i_mode)) {
        return 0;
    }

    // 读取文件第一个磁盘块
    bh = sb_bread(inode->i_sb, 0);
    if (!bh) {
        return -ENOENT;
    }

    // 校验ELF魔数
    const char *magic = bh->b_data;
    iself = (magic[0] == 0x7F) && (magic[1] == 'E') && (magic[2] == 'L') && (magic[3] == 'F');
    
    printk(KERN_INFO "[xattracl] magic: %02X%02X%02X%02X iself: %d\n",
           (unsigned char)magic[0], (unsigned char)magic[1], (unsigned char)magic[2], (unsigned char)magic[3], iself);

    brelse(bh);
    return iself;
}

路径获取使用内核标准d_path()函数,注意缓冲区的正确管理:

char *xattracl_get_realpath(struct path *path) {
    char *buf = (char *)__get_free_page(GFP_NOFS);
    if (!buf) {
        return NULL;
    }
    // 获取路径,返回值指向buf中的有效路径
    char *realpath = d_path(path, buf, PAGE_SIZE);
    if (IS_ERR(realpath)) {
        free_page((unsigned long)buf);
        return NULL;
    }
    // 复制到可长期保存的kmalloc缓冲区
    char *ret = kstrdup(realpath, GFP_NOFS);
    free_page((unsigned long)buf);
    return ret;
}

2. 合规的LSM共享库加载检查方式

不要使用file_open钩子,该钩子范围过大且易触发递归问题,推荐使用官方设计的精准钩子:

2.1 使用mmap_file钩子

共享库加载最终会通过mmap映射到进程内存,mmap_file钩子专门用于检查文件映射操作,可过滤出带执行权限的映射(共享库加载的特征):

static int xattracl_mmap_file(struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags) {
    // 仅拦截带执行权限的映射
    if (!(prot & PROT_EXEC)) {
        return 0;
    }

    // 检查是否为ELF文件
    int iself = xattracl_file_magic_check_elf(file);
    if (!iself) {
        return 0;
    }

    // 检查扩展属性
    struct inode *inode = file_inode(file);
    char value[XATTRACL_XATTR_VALUE_SIZE];
    int size = __vfs_getxattr(file->f_path.dentry, inode, XATTRACL_XATTR_NAME, value, sizeof(value));
    
    // 无对应xattr或值不匹配则拒绝加载
    if (size < 0 || strncmp(value, XATTRACL_XATTR_ACTION_ALLOW, size) != 0) {
        char buf[PAGE_SIZE];
        printk(KERN_INFO "[xattracl] Deny loading: %s\n", d_path(&file->f_path, buf, sizeof(buf)));
        return -EPERM;
    }

    return 0;
}

// 注册钩子
static struct security_hook_list xattracl_hooks[] __lsm_ro_after_init = {
    LSM_HOOK_INIT(mmap_file, xattracl_mmap_file),
    // 其他需要的钩子...
};

2.2 使用bprm_check_security钩子

该钩子在进程执行二进制文件(包括共享库依赖加载)前触发,适合检查可执行文件的合法性:

static int xattracl_bprm_check_security(struct linux_binprm *bprm) {
    struct file *file = bprm->file;
    int iself = xattracl_file_magic_check_elf(file);
    if (!iself) {
        return 0;
    }

    // 检查xattr逻辑同上
    struct inode *inode = file_inode(file);
    char value[XATTRACL_XATTR_VALUE_SIZE];
    int size = __vfs_getxattr(file->f_path.dentry, inode, XATTRACL_XATTR_NAME, value, sizeof(value));
    
    if (size < 0 || strncmp(value, XATTRACL_XATTR_ACTION_ALLOW, size) != 0) {
        char buf[PAGE_SIZE];
        printk(KERN_INFO "[xattracl] Deny execution: %s\n", d_path(&file->f_path, buf, sizeof(buf)));
        return -EPERM;
    }

    return 0;
}

// 注册钩子
LSM_HOOK_INIT(bprm_check_security, xattracl_bprm_check_security),

2.3 方案优势

  • 精准拦截:仅针对可执行文件/共享库的加载场景,避免无差别拦截普通文件打开。
  • 无递归风险:直接使用传入的内核对象操作,无需重新打开文件,不会触发自身钩子递归。
  • 符合LSM规范:这两个钩子是官方推荐的可执行文件安全检查入口,SELinux、AppArmor均使用类似逻辑实现权限管控。

内容的提问来源于stack exchange,提问作者Pairman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 01:47:23