lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <m2zm6f5nzm.fsf@cerbere.dyndns.info>
Date:	Thu, 15 Mar 2007 01:50:21 +0100
From:	Samir Bellabes <sam@...ack.fr>
To:	Evgeniy Polyakov <johnpol@....mipt.ru>
Cc:	netdev@...r.kernel.org
Subject: Re: [RFC] [PATCH] Network Events Connector

Evgeniy Polyakov <johnpol@....mipt.ru> writes:

> On Fri, Feb 09, 2007 at 05:43:14AM +0100, Samir Bellabes (sam@...ack.fr) wrote:
>> Hi,
>> 
>> Here is a new feature which can help firewalls to be more application
>> aware, so more useful for people.
>> 
>> Our previous discussion about cn_net and firewalls:
>> http://marc2.theaimsgroup.com/?t=115976957500002&r=1&w=2
>> 
>> Please, I would really like to have feedback and comments on that tool,
>> in order to improve it.
>
> Technical side does have problems.
> 1. your way to delete and check events is wrong - there is no need to
> allocate new event and search for it in the hash table to remove - use
> values as is.
> 3. why hash table and not rb tree?

You are right, I have rewrite this part of the system, using rbtree

Here is patch to apply on top of the previous 'initialisation path'
patch.

commit 5110880bc67e8329671ffa596cd899995c05ec82
Author: Samir Bellabes <sam@...ack.fr>
Date:   Thu Mar 15 01:42:48 2007 +0100

    [PATCH] cn_net: store event's configuration in RB tree
    
    Noticed by Evgeniy Polyakov <johnpol@....mipt.ru>
    
    Signed-off-by: Samir Bellabes <sam@...ack.fr>

diff --git a/drivers/connector/cn_net.c b/drivers/connector/cn_net.c
index c9eb53e..a15f67b 100644
--- a/drivers/connector/cn_net.c
+++ b/drivers/connector/cn_net.c
@@ -22,7 +22,7 @@ #include <net/inet_sock.h>
 #include <linux/in.h>
 #include <linux/ipv6.h>
 #include <linux/in6.h>
-#include <linux/jhash.h>
+#include <linux/rbtree.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/random.h>
@@ -34,10 +34,8 @@ static struct cb_id cn_net_event_id = { 
 static char cn_net_event_name[] = "cn_net_event";
 static int secondary = 0;
 
-static struct list_head *hash = NULL;
-static rwlock_t hash_lock = RW_LOCK_UNLOCKED;
-static int hash_size = 4;
-module_param(hash_size, uint, 0600);
+struct rb_root event_tree = RB_ROOT;
+static rwlock_t event_lock = RW_LOCK_UNLOCKED;
 
 #if defined(CONFIG_NET_EVENTS)
 #define MY_NAME THIS_MODULE->name
@@ -61,172 +59,198 @@ static unsigned int is_same_event(struct
 }
 
 /**
- * check_event()
- * look for a match in the hash table
- * Returns 1 if data is in the hash table
+ * lookup_event()
+ * look for a match in the rbtree
+ * returns address of the wanted element if it is in the rbtree, or NULL
  */
-static unsigned int check_event(struct event_list *data) {
-	unsigned int err = 0, h = 0;
-	struct list_head *l;
-	struct event_list *evl;
-
-	h = jhash(&(data->ev), sizeof(struct event), 0) % hash_size;
-
-	read_lock(&hash_lock);
-	l = &hash[h];
-	list_for_each_entry(evl, l, list) {
-		if (is_same_event(evl->ev, data->ev)) {
-			err = 1;
-			break;
+static struct event_node *lookup_event(struct event ev) {
+	struct rb_node *rb_node = event_tree.rb_node;
+
+	read_lock(&event_lock);
+
+	while (rb_node) {
+		struct event_node *cur = rb_entry(rb_node, struct event_node, ev_node);
+		
+		if (is_same_event(cur->ev, ev)) {
+			read_unlock(&event_lock);
+			return cur;
 		}
+
+		if (ev.syscall_num < cur->ev.syscall_num)
+			rb_node = rb_node->rb_left;
+		else if (ev.syscall_num > cur->ev.syscall_num)
+			rb_node = rb_node->rb_right;
+		else if (ev.protocol < cur->ev.protocol)
+			rb_node = rb_node->rb_left;
+		else if (ev.protocol > cur->ev.protocol)
+			rb_node = rb_node->rb_right;
 	}
-	read_unlock(&hash_lock);
-	return err;
+
+	read_unlock(&event_lock);
+	return NULL;
 }
 
-/**
- * check_wanted_data
- * We don't send unwanted informations to userspace, according to the
- * dynamic configuration in the hash table.
- * @sock: sock which is changing its state
- * Returns: 1 if data have to be send to userspace
+/** 
+ * check_wanted_data()
+ * we don't send unwanted informations to userspace, according to the
+ * dynamic configuration in the rbtree
  */
-static int check_wanted_data(struct sock *sk, enum cn_net_socket syscall_num) {
-	struct event_list *data = NULL;
-	unsigned int err = 0;
-
-	if (!sk)
-		return -EINVAL;
+static int check_wanted_event(struct sock *sk, enum cn_net_socket syscall_num) {
+	int err = -EINVAL;
+	struct event ev;
 	
-	data = kzalloc(sizeof(struct event_list), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-	data->ev.syscall_num = syscall_num;
-	data->ev.protocol = sk->sk_protocol;
-	INIT_LIST_HEAD(&(data->list));
+	if (!sk)
+		return err;
 
+	ev.syscall_num = syscall_num;
+	ev.protocol = sk->sk_protocol;
+	       
 	/* check if the event is already registered */
-	err = check_event(data);
-	kfree(data);
+	if (lookup_event(ev))
+		err = 0;
+
 	return err;
 }
 
 /**
- * dump_event() dumps the entire hash_table in log
+ * dump_event()
+ * dump the entire rbtree in log
  */
-static void dump_event(struct list_head *hash) {
-	unsigned int i = 0;
-	struct list_head *l = NULL;
-	struct event_list *evl = NULL;
-	
-	read_lock(&hash_lock);
-	for (i = 0; i < hash_size; i++) {
-		l = &hash[i];
-		printk(KERN_INFO "----\n");
-		printk(KERN_INFO "%d.\n", i);
-		list_for_each_entry(evl, l, list) {
-			printk(KERN_INFO " %d:%s\n",
-			       evl->ev.protocol, syscall_name[evl->ev.syscall_num]);
-		}
-	}
-	read_unlock(&hash_lock);
-
-	return;
+static void dump_event(void) {
+	struct rb_node *p = NULL ;
+	struct event_node *tmp = NULL;
+
+	read_lock(&event_lock);
+	p = rb_first(&event_tree);
+	while (p) {
+		tmp = rb_entry(p, struct event_node, ev_node);
+		printk(KERN_INFO "%d:%s\n",
+		       tmp->ev.protocol, syscall_name[tmp->ev.syscall_num]);
+		p = rb_next(p);
+	};
+	read_unlock(&event_lock);
 }
 
 /**
- * deletion of all elements in the hashtable
+ * remove_all_event()
+ * delete all events registered in the rbtree
  */
-static enum ack_err clean_all_event(struct list_head *hash) {
-	unsigned int i = 0;
-	struct event_list *evl = NULL;
-	
-	write_lock(&hash_lock);
-	for (i = 0; i < hash_size; i++) {
-		while(!list_empty(&hash[i])) {
-			evl = list_entry(hash[i].next, struct event_list, list);
-			if (evl) {
-				list_del(&evl->list);
-				kfree(evl);
-			}
-		}
+static enum ack_err remove_all_event(void) {
+	struct rb_node *p = NULL;
+	struct event_node *cur = NULL;
+
+	write_lock(&event_lock);	
+	while ((p = rb_first(&event_tree)) != NULL) {
+		cur = rb_entry(p, struct event_node, ev_node);
+		rb_erase(p, &event_tree);
+		kfree(cur);
 	}
-	write_unlock(&hash_lock);
-	/* hash table is now empty */
+	write_unlock(&event_lock);
+
+	/* rbtree is now empty */
 	return CN_NET_ACK_SUCCES;
 }
 
-/**
- * add a entry to the hash table
- * we are checking if we register a same event twice
+/** 
+ * alloc_event()
+ * alloc memory for a event_node, and return pointer to it
  */
-static enum ack_err add_event(struct list_head *hash, struct event ev) {
+static struct event_node *alloc_event(void) {
+	struct event_node *evn = NULL;
+	evn = kzalloc(sizeof(struct event_node), GFP_KERNEL);
+	return evn;
+}
 
-	struct event_list *data = NULL;
-	unsigned int h = 0;
-	enum ack_err err = CN_NET_ACK_SUCCES;
-	
-	data = kzalloc(sizeof(struct event_list), GFP_KERNEL);
-	if (!data) {
-		err = CN_NET_ACK_ENOMEM;
-		return err;
+/**
+ * insert_event()
+ * insert a event in the rbtree
+ * we are checking if we are trying to register a same event twice
+ */
+static enum ack_err insert_event(struct event ev) {
+	struct rb_node **rb_link, *rb_parent;
+	struct event_node *new_evn;
+	enum ack_err ret = CN_NET_ACK_SUCCES;
+
+	rb_link = &event_tree.rb_node;
+	rb_parent = NULL;
+
+	write_lock(&event_lock);
+
+	while(*rb_link) {
+		struct event_node *tmp;
+
+		rb_parent = *rb_link;
+		tmp = rb_entry(rb_parent, struct event_node, ev_node);
+		
+		if (ev.syscall_num < tmp->ev.syscall_num)
+			rb_link = &rb_parent->rb_left;
+		else if (ev.syscall_num > tmp->ev.syscall_num)
+			rb_link = &rb_parent->rb_right;
+		else if (ev.protocol < tmp->ev.protocol)
+			rb_link = &rb_parent->rb_left;
+		else if (ev.protocol > tmp->ev.protocol)
+			rb_link = &rb_parent->rb_right;
+		else {
+			/* event is already registered */
+			ret = CN_NET_ACK_EINCONFIG;
+			goto out;
+		}
 	}
-	data->ev.syscall_num = ev.syscall_num;
-	data->ev.protocol = ev.protocol;
-	INIT_LIST_HEAD(&(data->list));
 
-	/* check if the event is already registered */
-	if (check_event(data)) {
-		kfree(data);
-		err = CN_NET_ACK_EINCONFIG;
-		return err;
+	/* no match: event is added to the tree */
+	if ((new_evn = alloc_event()) != NULL) {
+		new_evn->ev.syscall_num = ev.syscall_num;
+		new_evn->ev.protocol = ev.protocol;
+	} else {
+		/* can't allocate memory, exiting */
+		ret = CN_NET_ACK_ENOMEM;
+		goto out;
 	}
-	h = jhash(&(data->ev), sizeof(struct event), 0) % hash_size;
 
-	write_lock(&hash_lock);
-	list_add_tail(&data->list, &hash[h]);
-	write_unlock(&hash_lock);
+	rb_link_node(&new_evn->ev_node, rb_parent, rb_link);
+	rb_insert_color(&new_evn->ev_node, &event_tree);
 
-	return err;
+out:
+	write_unlock(&event_lock);
+	return ret;
 }
 
 /**
- * delete a entry from the hash table
- * we are checking if we delete a unregistered event
+ * remove_event()  
+ * delete a entry from the rbtree
+ * we are checking if we are trying to delete a unregistered event
  */
-static enum ack_err del_event(struct list_head *hash, struct event ev) {
-	
-	struct event_list *data;
-	unsigned int h = 0;
-	enum ack_err err = CN_NET_ACK_EINCONFIG;
-	struct list_head *l = NULL;
-	struct event_list *evl = NULL;
-
-	data = kzalloc(sizeof(struct event_list), GFP_KERNEL);
-	if (!data) {
-		err = CN_NET_ACK_ENOMEM;
-		return err;
-	}
-	data->ev.syscall_num = ev.syscall_num;
-	data->ev.protocol = ev.protocol;
-	INIT_LIST_HEAD(&(data->list));
-
-	h = jhash(&(data->ev), sizeof(struct event), 0) % hash_size;
-
-	write_lock(&hash_lock);
-	l = &hash[h];
-	list_for_each_entry(evl, l, list) {
-		if (is_same_event(evl->ev, data->ev)) {
-			list_del(&evl->list);
-			kfree(evl);
-			err = CN_NET_ACK_SUCCES;
+static enum ack_err remove_event(struct event ev) {
+	struct event_node *cur = NULL;
+	enum ack_err ret = CN_NET_ACK_EINCONFIG;
+	struct rb_node *rb_node = event_tree.rb_node;
+
+	write_lock(&event_lock);
+
+	while (rb_node) {
+		cur = rb_entry(rb_node, struct event_node, ev_node);
+		
+		if (is_same_event(cur->ev, ev))
 			break;
-		}
+
+		if (ev.syscall_num < cur->ev.syscall_num)
+			rb_node = rb_node->rb_left;
+		else if (ev.syscall_num > cur->ev.syscall_num)
+			rb_node = rb_node->rb_right;
+		else if (ev.protocol < cur->ev.protocol)
+			rb_node = rb_node->rb_left;
+		else if (ev.protocol > cur->ev.protocol)
+			rb_node = rb_node->rb_right;
 	}
-	write_unlock(&hash_lock);
-	kfree(data);
 
-	return err;
+	if (rb_node) {
+		rb_erase(&cur->ev_node, &event_tree);
+		kfree(cur);
+		ret = CN_NET_ACK_SUCCES;
+	}
+	write_unlock(&event_lock);
+
+	return ret;
 }
 
 /**
@@ -261,13 +285,13 @@ static enum ack_err do_config(struct msg
 
 	switch (cfg->config_cmd) {
 	case CN_NET_CONFIG_ADD:
-		err = add_event(hash, cfg->ev);
+		err = insert_event(cfg->ev);
 		break;
 	case CN_NET_CONFIG_DEL:
-		err = del_event(hash, cfg->ev);
+		err= remove_event(cfg->ev);
 		break;
 	case CN_NET_CONFIG_FLUSH:
-		err = clean_all_event(hash);
+		err = remove_all_event();
 		break;
 	default:
 		err = CN_NET_ACK_EINTYPE;
@@ -353,8 +377,8 @@ void cn_net_ctl(void *data) {
 	case CN_NET_IGNORE:     /* userspace is unregistering */
 		atomic_dec(&net_event_num_listeners);
 		break;
-	case CN_NET_DUMP:     /* dumping hash table -- debug purpose */
-		dump_event(hash);
+	case CN_NET_DUMP:     /* dumping the rbtree -- debug purpose */
+		dump_event();
 		break;
 	default:
 		err = CN_NET_ACK_EINTYPE;
@@ -485,7 +509,7 @@ out:
 static int cn_net_socket_listen(struct socket *sock, int backlog) {
 
 	DEBUGP(KERN_INFO "cn_net_socket_listen\n");
-	if (check_wanted_data(sock->sk, CN_NET_SOCKET_LISTEN) > 0)
+	if (check_wanted_event(sock->sk, CN_NET_SOCKET_LISTEN) == NULL)
 		cn_net_send_event(sock->sk, NULL, CN_NET_SOCKET_LISTEN);
 
 	return 0;
@@ -495,7 +519,7 @@ static int cn_net_socket_bind(struct soc
 			      struct sockaddr *address, int addrlen) {
 
 	DEBUGP(KERN_INFO "cn_net_socket_bind\n");
-	if (check_wanted_data(sock->sk, CN_NET_SOCKET_BIND) > 0)
+	if (check_wanted_event(sock->sk, CN_NET_SOCKET_BIND) == NULL)
 		cn_net_send_event(sock->sk, address, CN_NET_SOCKET_BIND);
 
 	return 0;
@@ -504,7 +528,7 @@ static int cn_net_socket_bind(struct soc
 static int cn_net_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) {
 	
 	DEBUGP(KERN_INFO "cn_net_socket_connect\n");
-	if (check_wanted_data(sock->sk, CN_NET_SOCKET_CONNECT) > 0)
+	if (check_wanted_event(sock->sk, CN_NET_SOCKET_CONNECT) == NULL)
 		cn_net_send_event(sock->sk, address, CN_NET_SOCKET_CONNECT);
 
 	return 0;
@@ -513,7 +537,7 @@ static int cn_net_socket_connect(struct 
 static int cn_net_socket_shutdown(struct socket *sock, int how) {
 
 	DEBUGP(KERN_INFO "cn_net_socket_shutdown\n");
-	if (check_wanted_data(sock->sk, CN_NET_SOCKET_SHUTDOWN) > 0)
+	if (check_wanted_event(sock->sk, CN_NET_SOCKET_SHUTDOWN) == NULL)
 		cn_net_send_event(sock->sk, NULL, CN_NET_SOCKET_SHUTDOWN);
 
 	return 0;
@@ -522,7 +546,7 @@ static int cn_net_socket_shutdown(struct
 static int cn_net_sk_free_security(struct sock *sk) {
 	
 	DEBUGP(KERN_INFO "cn_net_sk_free_security\n");
-	if (check_wanted_data(sk, CN_NET_SK_FREE_SECURITY) > 0)
+	if (check_wanted_event(sk, CN_NET_SK_FREE_SECURITY) == NULL)
 		cn_net_send_event(sk, NULL, CN_NET_SK_FREE_SECURITY);
 
 	return 0;
@@ -537,17 +561,7 @@ static struct security_operations cn_net
 };
 
 static int __init init(void) {
-	int err = 0, i = 0;
-
-	hash = kzalloc(sizeof(struct list_head) * hash_size, GFP_KERNEL);
-	if (!hash) {
-		printk(KERN_WARNING "cn_net: Failure can't alloc memory for hash\n");
-		err = -ENOMEM;
-		goto out;
-	}
-	
-	for (i = 0; i < hash_size; i++)
-		INIT_LIST_HEAD(&(hash[i]));
+	int err = 0;
 
 	err = cn_add_callback(&cn_net_event_id, cn_net_event_name, &cn_net_ctl);
 	if (err) {
@@ -574,9 +588,6 @@ out_security:
 	cn_del_callback(&cn_net_event_id);
 
 out_callback:
-	kfree(hash);
-
-out:
 	return err;
 }
 
@@ -594,10 +605,7 @@ static void __exit fini(void) {
 	cn_del_callback(&cn_net_event_id);
 	
 	/* clean memory */
-	if (hash) {
-		clean_all_event(hash);
-		kfree(hash);
-	}
+	remove_all_event();
 
 	printk(KERN_INFO "cn_net: network events module unloaded\n");
 }
diff --git a/include/linux/cn_net.h b/include/linux/cn_net.h
index 6604053..0d86715 100644
--- a/include/linux/cn_net.h
+++ b/include/linux/cn_net.h
@@ -76,8 +76,8 @@ struct event {
 	__u8 protocol;
 };
 
-struct event_list {
-	struct list_head list;
+struct event_node {
+	struct rb_node ev_node;
 	struct event ev;
 };
 
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ