Netlink configuration mechanism to increase the FSHOOK SandFS

As iptables rules can be configured to point Netfilter HOOK through netlink, I also want to implement a netlink fstables by the rules configured in FSHOOK HOOK specific point.

So I implemented a Demo, but not complete, since the latter have a problem, I do not want now to solve the problem, but to some description of the problem.

Devel branch of the code in sandfs_with_no_ebpf:
https://github.com/marywangran/sandfs_with_no_ebpf/tree/devel

Can be seen, the addition of a client directory, which is a python program, which is used to simulate fstables features:

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))

Very simple, that is a structure matches coming down through the core socket, which is received by the kernel netlink socket:

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);
		}
	}
}

Logic is very simple, i.e., generates a vfs_rule structure according to configuration information, inserted into a corresponding linked list HOOK, i.e. call sandfs_register_hook .

Now the question is, how vfs_rule the callback function func achieve? While the user mode can be poured down the policy and configuration, but there is no way to sink down function ah!

I tried to reconstruct 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;

I added a common gen_func function:

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;
}

But the overall feel looks ugly, so I #if 0 lost it!

Ah, yes, it seems to be the practice of using iptables, and prior to each match separately registered into the kernel, then closely packed rule.

When matching performed sequentially scanned arranged in the rules, and according to each of the match to match func. Like the iptables xt_ematch_foreach macro that.

You will find that these rules closely arranged is actually a table, so called iptables, ip6tables, arptables ...

I also realized if so, only with known fstables ... but I feel very close from the goal, unconsciously already in my gen_func ipt_do_table to move closer.

However, the tables have a downside, that tables of memory is allocated statically, add a new rule involves the following actions:

  1. Allocate new contiguous memory, the size of all the rules have size plus the total size of the new rule.
  2. The existing rules copied into the new memory.
  3. The new rule has been added to the memory after the new rules.
  4. Release the old memory.

If the rules are particularly large, tables will be very large, this is a very time-consuming operation, so I want to get at the problem of match match with a dynamic memory mode.


Wenzhou shoes wet, rain water will not be fat.

Released 1550 original articles · won praise 4786 · Views 10,650,000 +

Guess you like

Origin blog.csdn.net/dog250/article/details/104062659