File firewall redirfs

summary

The file firewall can be used to filter file operations, including but not limited to open read write close. Compared with LSM syshook, the firewall formed by inline hook hijacking is more stable and capable. Although there seems to be some problems with driver unloading at present, it has strong filtering ability for file operations.

Core principles

Since you want to filter file behavior, you must have function hijacking. Redirfs adopts the method of embedding driver redirfs between vfs and real file system. In brief, struct inode, struct dentry and struct file belong to vfs level concepts, and all have the operation set of each file. Real file systems have their own - xx_inode xx_dentry et al. vfs will call the file operation set in the real file system, and the system call will call the file operation set in vfs. Therefore, the hierarchical relationship of sys - > vfs -- > file system is finally formed. At this time, redirfs constructs its own rfs_inode operation set and form operation embedded capability. The file operation process of the kernel becomes

sys – > VFS – > redfs – > file operation process of file system. Of course, during this process, redirfs will save and call the original file operation set to ensure the stability of the original logic.

Core replacement at

rfs_inode_set_default_fop

#define PROTOTYPE_FOP(op, new_op) \
    RFS_ADD_OP_MGT(ri_new->f_op_new, inode->i_fop, op, new_op);
    FUNCTION_FOP_open // a watermark for rfs_cast_to_rfile
    FUNCTION_FOP_release
#undef PROTOTYPE_FOP

    inode->i_fop = &ri_new->f_op_new;

Macro function here_ FOP_ open FUNCTION_ FOP_ Release implements
ri_new->f_op_new.open = rfs_open
Ri_new->f_op_new.release = rfs_release.
Inode - > I_ fop = &ri_ new->f_ op_ new. You can see that the core file operation set of vfs has been modified. Of course, file and dentry have done similar operations.

Filter drive chain

redirfs defines struct RFs in order to realize the ability of multiple drivers to filter file systems at the same time_ flt

struct rfs_flt {
    struct list_head list;
    struct rfs_op_info cbs[RFS_INODE_MAX][RFS_OP_MAX];
    struct module *owner;
    struct kobject kobj;
    char *name;
    int priority;
    int paths_nr;
    spinlock_t lock;
    atomic_t active;
    atomic_t count;
    struct redirfs_filter_operations *ops;
};
Filter drive

Add drive chain

Set_operations will register multiple file operations to the redifs driver, op_id determines the file type and operation type, pre_cb,post_cb determines the address of the callback function and finally associates it with rfs_root_list linked list
Redirfs_op_info sets the hook function through an array for specific operations on specific files
rfs_flt sets the hook function through a two-dimensional matrix

#define  RFS_OP_IDC(itype, op_id) (itype<<16 | op_id)
#define  RFS_IDC_TO_ITYPE(idc) ((enum rfs_inode_type) (((idc) >> 16) & 0xFFFF))
#define  RFS_IDC_TO_OP_ID(idc) ((enum rfs_op_id) ((idc) & 0xFFFF))

it = RFS_IDC_TO_ITYPE(rargs->type.id);                    //RFS_INODE_MAX
op_id = RFS_IDC_TO_OP_ID(rargs->type.id);                      //RFS_OP_MAX

enum redirfs_op_idc {
 REDIRFS_NONE_DOP_D_REVALIDATE = RFS_OP_IDC(RFS_INODE_DNONE, RFS_OP_d_revalidate),
 ......
}

Here is a huge enumeration type redirfs_op_idc is used to define the properties and operation behavior of various files.

Ergodic drive chain


The traversal drive is the reverse process.

enum rfs_inode_type{

    /* dentry */
    RFS_INODE_DNONE, /* negative dentry */
    RFS_INODE_DSOCK, /* dentry for sock */
    RFS_INODE_DLINK, /* dentry for link */
    RFS_INODE_DREG,  /* dentry for dreg */
    RFS_INODE_DBULK,
    RFS_INODE_DDIR,
    RFS_INODE_DCHAR,
    RFS_INODE_DFIFO,

    /* inode */
    RFS_INODE_SOCK,
    RFS_INODE_LINK,
    RFS_INODE_REG,
    RFS_INODE_BULK,
    RFS_INODE_DIR,
    RFS_INODE_CHAR,
    RFS_INODE_FIFO,

    /* the last enum value, also stands for *any* */
    RFS_INODE_MAX
};


enum rfs_op_id {

    // dentry
    RFS_OP_d_start, /* start of the range */
    RFS_OP_d_revalidate,
    RFS_OP_d_weak_revalidate,
    RFS_OP_d_hash,
    RFS_OP_d_compare,
    RFS_OP_d_delete,
    RFS_OP_d_init,
    RFS_OP_d_release,
    RFS_OP_d_prune,
    RFS_OP_d_iput,
    RFS_OP_d_dname,
    RFS_OP_d_automount,

.........
}

From a technical point of view, there is nothing too novel, but the author's code foundation is really strong, you can learn from it.

Keywords: Linux

Added by jbatty on Wed, 19 Jan 2022 06:58:12 +0200