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

内核模块阻止特定文件写入后文件内容被清空的问题排查求助

问题成因分析

核心原因:文件截断操作早于sys_write执行

当用户通过覆盖式写入(比如echo "content" > authorized_keys)操作目标文件时,sys_open/sys_openat系统调用会先执行O_TRUNC标志对应的截断动作——直接将文件长度置为0,之后才会调用sys_write。你只拦截了sys_write但未阻止前置的截断操作,因此文件内容会被清空。

而钩子sys_openat修改文件描述符模式的方案失效,是因为O_TRUNC的截断动作在文件打开时已经完成,后续修改模式无法回滚该操作。

次要原因:sys_write钩子的返回逻辑误导应用层

你直接返回regs->dx(应用期望写入的字节数),会让应用误以为写入成功,可能触发后续的文件指针调整、缓存刷新等操作,进一步导致文件状态异常。


排查与解决方向

1. 拦截文件打开阶段的截断标志

针对目标文件,在sys_openat钩子中清除O_TRUNC、O_CREAT等会修改文件的标志,同时保留应用层感知的“打开成功”状态:

static asmlinkage long my_openat(const struct pt_regs *regs) {
    const char __user *filename = (const char __user *)regs->si;
    int flags = (int)regs->dx;
    struct path path;
    char buf[256];

    // 将用户空间文件名解析到内核空间
    if (getname(filename, &path) != 0) {
        return orig_openat(regs);
    }
    d_path(&path, buf, sizeof(buf));

    // 匹配目标文件的完整路径(避免误拦截同名文件)
    if (strstr(buf, "/authorized_keys") != NULL) {
        // 清除截断和创建标志
        flags &= ~(O_TRUNC | O_CREAT);
        // 移除写入权限,保留只读模式
        flags &= ~(O_WRONLY | O_RDWR);
        flags |= O_RDONLY;
        // 修改寄存器中的flags参数
        regs->dx = flags;
    }

    path_put(&path);
    return orig_openat(regs);
}

2. 全面拦截所有文件修改类系统调用

除了sys_write,还需要拦截sys_pwrite64、sys_writev、sys_pwritev等写入类调用,同时覆盖sys_truncate、sys_ftruncate等直接修改文件长度的系统调用,确保没有遗漏的修改路径。

3. 修正sys_write钩子的偏移量处理

直接返回期望字节数会导致应用层误以为文件指针已移动,需恢复文件偏移量以避免后续异常:

static asmlinkage long my_write(const struct pt_regs *regs){
    unsigned int fd = (unsigned int)regs->di;
    struct task_struct* task = current;
    struct file* opened_file = task->files->fdt->fd[fd];
    loff_t original_pos;

    if(opened_file){
        if(strcmp(opened_file->f_path.dentry->d_name.name, "authorized_keys") == 0){
            pr_info("Preventing write...\n");
            // 保存并恢复原文件偏移量
            original_pos = opened_file->f_pos;
            opened_file->f_pos = original_pos;
            return regs->dx;
        }
    }else{
        pr_info("FD is ZERO\n");
    }
    
    return orig_write(regs);
}

4. 分场景验证问题

  • 测试追加写入(echo "content" >> authorized_keys):该场景不会触发O_TRUNC,如果文件未被清空,可确认问题根源来自open阶段的截断。
  • 查看内核日志(dmesg),确认open和write阶段的钩子是否被正确触发,参数修改是否生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 07:40:25