为SandFS的FSHOOK增加netlink配置机制

正如iptables可以通过netlink将规则配置到Netfilter的HOOK点一样,我也希望实现一个fstables通过netlink将规则配置在FSHOOK的特定HOOK点。

于是我实现了一个Demo,但并没有完成,因为后面遇到了问题,我不希望现在就解决问题,而是希望把问题描述一番。

代码在sandfs_with_no_ebpf的devel分支:
https://github.com/marywangran/sandfs_with_no_ebpf/tree/devel

可以看到,增加了一个client目录,里面是一个python程序,它用来模拟fstables的功能:

import os
import socket
import struct

NETLINK_FSHOOK = 31

SANDFS_LOOKUP = 0
SANDFS_OPEN = 1
SANDFS_CLOSE = 2
SANDFS_READ = 3
SANDFS_WRITE = 4

# TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO

sock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, NETLINK_FSHOOK)
sock.bind((os.getpid(), RTMGRP_LINK))

name = bytes('test1'.encode('utf-8'))
opt = 'A'
hooknum = SANDFS_READ
uid = 1000
path = bytes('N/A'.encode('utf-8'))
pos = -1
count = 10
buf = bytes('N/A'.encode('utf-8'))

data = struct.pack("@32sBII32sII32s", name, opt, hooknum, uid, path, pos, count, buf);
sock.sendto(data, (0, 0))

非常简单,就是把一个matches结构体通过socket灌进内核,内核通过netlink套接字来接收它:

static void rule_nl_recv_msg(struct sk_buff *skb)
{
    struct rule_match *match;
    struct vfs_rule *rule;
    char *head;
    char name[DESC_MAX] = {0};
    int err = 0;

    head = (char *)skb->data;
    strncpy(name, head, DESC_MAX);
    head += DESC_MAX;
    match = (struct rule_match *)head;
    printk(KERN_INFO "##### opt:%c hook:%x   uid:%x  path:%s  pos:%x  count:%x  buff:%s\n",
            match->option,
            match->hooknum,
            match->uid,
            match->path,
            match->pos,
            match->count,
            match->buff);

    if (match->option == 'A') {
        rule = kzalloc(sizeof(struct vfs_rule), GFP_KERNEL);
        rule->hooknum = match->hooknum;
        strcpy(&rule->name[0], name);
        memcpy(&rule->match, match, sizeof(struct rule_match));
        err = sandfs_register_hook(rule);
    } else if (match->option == 'D') {
        rule = sandfs_unregister_hook(match->hooknum, name);
        if (rule) {
            kfree(rule);
        }
    }
}

逻辑非常简单,即根据配置信息生成一个vfs_rule结构体,插入对应HOOK的链表,即调用 sandfs_register_hook

现在问题来了,vfs_rule的func回调函数如何实现?虽然用户态可以灌下来策略和配置,但没有办法灌下来函数啊!

我试着重构FS_HOOK:

 inline int FS_HOOK(unsigned int hook, struct sandfs_args *args, void *priv)
 {
        int err = FS_ACCEPT;
@@ -54,9 +90,11 @@ inline int FS_HOOK(unsigned int hook, struct sandfs_args *args, void *priv)

        read_lock(&lock);
        list_for_each_entry(rule, &list, list) {
-               if (!rule->func)
-                       continue;
-               err = rule->func(hook, args, priv, &handled);
+               if (!rule->func) {
+                       err = gen_func(rule, args, priv, &handled);
+               } else {
+                       err = rule->func(hook, args, priv, &handled);
+               }
                if (handled == 1) {
                        read_unlock(&lock);
                        return err;

我增加了一个通用的gen_func函数:

static int gen_func(struct vfs_rule *rule, struct sandfs_args *args, void *priv, int *handled)
{
    int err = FS_ACCEPT;
#if 0
    struct rule_match match;
    int num;
    struct cred *cred;
    kuid_t id;
    unsigned int plen;

    match = rule->match;
    num = args->num_args;
    if (num >= 2) {
        cred = (struct cred *)largs->args[SANDFS_IDX_CRED].value;
        id = cred->uid;
        plen = largs->args[SANDFS_IDX_PATH].size;
        path = (char *)largs->args[SANDFS_IDX_PATH].value;
        if (num == 2 && match->uid == id.val && !strncmp(path, match->path, plen)) {
            err = FS_DROP;
            *handled = 1;
        }
    }
    if (num >= 4) {
    }
    if (num >= 5) {
    }
#endif
    return err;
}

但总觉得长得不好看,于是我#if 0掉了它!

嗯,是的,看来必须采用iptables的做法了,事先将各个match分别注册进内核,然后将rule紧密排列。

匹配进行的时候,顺序扫描这些排列着的rules,然后根据每一个match的func去进行匹配。就像iptables的xt_ematch_foreach宏那样。

你会发现,紧密排列的这些rules其实就是一张表,所以叫做iptables,ip6tables,arptables…

如果我也这么实现,才配叫做fstables…不过我觉得离目标很近了,不自觉中我的gen_func已经在向ipt_do_table靠拢了。

不过,这种tables有个弊端,那就是tables的内存是静态分配的,新增加一条规则所牵扯的动作如下:

  1. 分配新的连续内存,大小为所有已经rules的大小加上新rule的总大小。
  2. 将已有的rules拷贝进新内存。
  3. 将新rule追加到新内存已有rules之后。
  4. 释放旧内存。

如果规则特别多,tables就会非常大,这是一个非常耗时的操作,于是我在想用一种动态内存的方式搞定match匹配的问题。


浙江温州皮鞋湿,下雨进水不会胖。

原文链接: https://blog.csdn.net/dog250/article/details/104062659

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    为SandFS的FSHOOK增加netlink配置机制

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/406133

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月26日 上午9:38
下一篇 2023年4月26日 上午9:38

相关推荐