玩坏Linux内核之禁止删除文件

文章介绍了如何通过hookext4文件系统的inode_operations结构中的unlink函数,以禁止包括root用户在内的所有用户删除文件。通过获取ext4_dir_inode_operations地址,关闭写保护,替换unlink函数为自定义函数,然后开启写保护,从而实现文件删除保护。模块加载和卸载时分别进行原函数的保存和恢复。
摘要由CSDN通过智能技术生成

今天我们来在内核里做点有意思的事----禁止用户删除文件(包括root用户)

先来一点原理

删除文件的流程如下:

  • 应用层
    rm -> unlinkat()
  • 内核
    sys_unlinkat() -> do_unlinkat() -> vfs_unlink()

最后vfs_unlink()会调用具体文件系统的unlink()函数, 例如ext4文件系统对应的ext4_unlink()

几种思路

如果想禁止删除文件, hook上述的任意一个函数都可以实现, 最简单的应该是hook系统调用sys_unlinkat()了, 这种方式网上很多教程, 不是我们今天要讲的; 当然还可以使用inline hookdo_unlinkat()或者vfs_unlink(), 这种方式稍微复杂一些, 我们今天也不讨论; 今天我们搞一个小众的玩法: hook具体文件系统的unlink()实现.

我们的玩法

我们今天以ext4文件系统为例, 通过替换inode_operations里的unlink函数指针实现禁止删除文件的目的.

流程如下:

  1. 使用kallsyms_lookup_name()获取ext4文件系统的struct inode_operations结构地址
  2. 关闭写保护
  3. struct inode_operations中的unlink换成我们自己的函数
  4. 开启写保护
  5. 在我们自己的函数中拒绝删除文件

代码如下(5.4内核测试通过):

// 获取ext4文件系统的struct inode_operations结构地址
void* __get_ext4_inode_ops(void)
{
    void *p = (void *)kallsyms_lookup_name("ext4_dir_inode_operations");
    return p;
}

// 关闭写保护
unsigned long write_protect_disable(void)
{
    unsigned long cr0 = 0;
    unsigned long ret = 0;

    // 获取原始cr0的值
#ifndef __LP64__
    asm volatile("movl %%cr0, %%eax": "=a"(cr0));
#else
    asm volatile("movq %%cr0, %%rax": "=a"(cr0));
#endif

    // 保存原始cr0的值
    ret = cr0;

    // 清除CR0寄存器的第16位(写保护位)
#ifndef __LP64__
    cr0 &= 0xfffeffff;
    asm volatile("movl %%eax, %%cr0":: "a"(cr0));
#else
    cr0 &= 0xfffffffffffeffff;
    asm volatile("movq %%rax, %%cr0":: "a"(cr0));
#endif

    // 返回原始cr0值
    return ret;
}

// 开启写保护
void write_protect_enable(unsigned long oldval)
{
    // 恢复cr0
#ifndef __LP64__
    asm volatile("movl %%eax, %%cr0":: "a"(oldval));
#else
    asm volatile("movq %%rax, %%cr0":: "a"(oldval));
#endif
}

// 我们的unlink
static int my_ext4_unlink(struct inode *dir, struct dentry *dentry)
{
    klogw(log_tag "you can not rm [%s]", dentry->d_name.name);
    return -1;
}

// 保存ext4文件系统的struct inode_operations结构地址
struct inode_operations *ext4_iops;
// 保存原来的unlink
int (*orig_ext4_unlink)(struct inode *dir, struct dentry *dentry);

/*
 * 模块初始化
 */
static __init int main_init(void)
{
    int rv = -1;
    unsigned long cr0;

    // 1. 获取ext4文件系统的struct inode_operations结构地址
    ext4_iops = __get_ext4_inode_ops();
    // 2. 替换我们的unlink
    orig_ext4_unlink = ext4_iops->unlink;
    cr0 = write_protect_disable();
    ext4_iops->unlink = my_ext4_unlink;    
    write_protect_enable(cr0);

    klogw(log_tag "kernel module load.");

    // 设置成功标识
    rv = 0x0;

    goto out;

out:
    return rv;
}

/*
 * 模块清理
 */
static __exit void main_exit(void)
{
    // 恢复原来的unlink
    unsigned long cr0;
    cr0 = write_protect_disable();
    ext4_iops->unlink = orig_ext4_unlink;
    write_protect_enable(cr0);

    klogw(log_tag "kernel module unload.");
}

module_init(main_init); 
module_exit(main_exit); 

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Kernel Module");
MODULE_AUTHOR("lee");

现在安装模块之后你应该就不能删除任何文件了, 快试一下吧!

都看到这里了,顺手点个 吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值