Message ID | 1262437456-24476-6-git-send-email-sam@synack.fr |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
Hi. On Sat, Jan 02, 2010 at 02:04:12PM +0100, Samir Bellabes (sam@synack.fr) wrote: > This patch adds the snet's subsystem responsive of managing events > > snet is using the word 'event' for a couple of values [syscall, protocol]. For > example, [listen, tcp] or [sendmsg, dccp] are events. > This patch introduces a hastable 'event_hash' and operations (add/remove/search..) > in order to manage which events have to be protected. > With the help of the communication's subsystem, managing orders are coming from > userspace. > > Signed-off-by: Samir Bellabes <sam@synack.fr> > --- > + > +extern unsigned int event_hash_size; > + > + > +static struct list_head *event_hash; > +static rwlock_t event_hash_lock = __RW_LOCK_UNLOCKED(); > + Those are way too generic names, please use snet_ prefix as you did in other places. I believe snet should be converted to RCU instead of rw locks. > +/* lookup for a event_hash - before using this function, lock event_hash_lock */ > +static struct snet_event_entry *__snet_event_lookup(const enum snet_syscall syscall, > + const u8 protocol) > +{ > + unsigned int h = 0; > + struct list_head *l; > + struct snet_event_entry *s; > + struct snet_event t; > + > + if (!event_hash) > + return NULL; > + > + /* building the element to look for */ > + t.syscall = syscall; > + t.protocol = protocol; > + > + /* computing its hash value */ > + h = jhash(&t, sizeof(struct snet_event), 0) % event_hash_size; You can have better distribution if not simply cut off the remainder. Also it is a rather expensive operation. > + l = &event_hash[h]; > + > + list_for_each_entry(s, l, list) { > + if ((s->se.protocol == protocol) && > + (s->se.syscall == syscall)) { > + return s; > + } > + } > + return NULL; > +} Below comments looks a little bit weird, was it generated automatically by editor? > +/* void snet_event_dumpall() */ > +/* { */ > +/* unsigned int i = 0; */ > +/* struct list_head *l; */ > +/* struct snet_event_entry *s; */ > + > +/* snet_dbg("entering\n"); */ > +/* read_lock_bh(&event_hash_lock); */ > +/* for (i = 0; i < (event_hash_size - 1); i++) { */ > +/* l = &hash[i]; */ > +/* list_for_each_entry(s, l, list) { */ > +/* snet_dbg("[%d, %d, %d]\n", i, */ > +/* s->se.protocol, s->se.syscall); */ > +/* } */ > +/* } */ > +/* read_unlock_bh(&event_hash_lock); */ > +/* snet_dbg("exiting\n"); */ > +/* return; */ > +/* } */ > +int snet_event_insert(const enum snet_syscall syscall, const u8 protocol) > +{ > + struct snet_event_entry *data = NULL; > + unsigned int h = 0; > + > + data = kzalloc(sizeof(struct snet_event_entry), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + write_lock_bh(&event_hash_lock); > + /* check if event is already registered */ > + if (!event_hash || __snet_event_lookup(syscall, protocol) != NULL) { > + write_unlock_bh(&event_hash_lock); > + kfree(data); > + return -EINVAL; > + } What about single error exiting point? > + > + data->se.syscall = syscall; > + data->se.protocol = protocol; > + INIT_LIST_HEAD(&(data->list)); > + h = jhash(&(data->se), sizeof(struct snet_event), 0) % event_hash_size; > + list_add_tail(&data->list, &event_hash[h]); > + write_unlock_bh(&event_hash_lock); > + > + return 0; > +} > +/* init function */ > +int snet_event_init(void) > +{ > + int err = 0, i = 0; > + > + event_hash = kzalloc(sizeof(struct list_head) * event_hash_size, > + GFP_KERNEL); > + if (!event_hash) { > + printk(KERN_WARNING > + "snet: can't alloc memory for event_hash\n"); > + err = -ENOMEM; > + goto out; > + } > + > + for (i = 0; i < event_hash_size; i++) > + INIT_LIST_HEAD(&(event_hash[i])); No need for double braces.
Hello Evgeniy, Evgeniy Polyakov <zbr@ioremap.net> writes: >> + >> +extern unsigned int event_hash_size; >> + > >> + >> +static struct list_head *event_hash; >> +static rwlock_t event_hash_lock = __RW_LOCK_UNLOCKED(); >> + > > Those are way too generic names, please use snet_ prefix as you did in > other places. done. thank you > I believe snet should be converted to RCU instead of rw locks. I see, I will investigated this idea. >> +/* lookup for a event_hash - before using this function, lock event_hash_lock */ >> +static struct snet_event_entry *__snet_event_lookup(const enum snet_syscall syscall, >> + const u8 protocol) >> +{ >> + unsigned int h = 0; >> + struct list_head *l; >> + struct snet_event_entry *s; >> + struct snet_event t; >> + >> + if (!event_hash) >> + return NULL; >> + >> + /* building the element to look for */ >> + t.syscall = syscall; >> + t.protocol = protocol; >> + >> + /* computing its hash value */ >> + h = jhash(&t, sizeof(struct snet_event), 0) % event_hash_size; > > You can have better distribution if not simply cut off the remainder. > Also it is a rather expensive operation. true, I replaced the modulo operation to a bitmask operations. >> + l = &event_hash[h]; >> + >> + list_for_each_entry(s, l, list) { >> + if ((s->se.protocol == protocol) && >> + (s->se.syscall == syscall)) { >> + return s; >> + } >> + } >> + return NULL; >> +} > > Below comments looks a little bit weird, was it generated automatically > by editor? no, it's was a unused debug function. I deleted this comment. >> +/* void snet_event_dumpall() */ >> +/* { */ >> +/* unsigned int i = 0; */ >> +/* struct list_head *l; */ >> +/* struct snet_event_entry *s; */ >> + >> +/* snet_dbg("entering\n"); */ >> +/* read_lock_bh(&event_hash_lock); */ >> +/* for (i = 0; i < (event_hash_size - 1); i++) { */ >> +/* l = &hash[i]; */ >> +/* list_for_each_entry(s, l, list) { */ >> +/* snet_dbg("[%d, %d, %d]\n", i, */ >> +/* s->se.protocol, s->se.syscall); */ >> +/* } */ >> +/* } */ >> +/* read_unlock_bh(&event_hash_lock); */ >> +/* snet_dbg("exiting\n"); */ >> +/* return; */ >> +/* } */ > >> +int snet_event_insert(const enum snet_syscall syscall, const u8 protocol) >> +{ >> + struct snet_event_entry *data = NULL; >> + unsigned int h = 0; >> + >> + data = kzalloc(sizeof(struct snet_event_entry), GFP_KERNEL); >> + if (!data) >> + return -ENOMEM; >> + >> + write_lock_bh(&event_hash_lock); >> + /* check if event is already registered */ >> + if (!event_hash || __snet_event_lookup(syscall, protocol) != NULL) { >> + write_unlock_bh(&event_hash_lock); >> + kfree(data); >> + return -EINVAL; >> + } > > What about single error exiting point? done, thanks >> + >> + data->se.syscall = syscall; >> + data->se.protocol = protocol; >> + INIT_LIST_HEAD(&(data->list)); >> + h = jhash(&(data->se), sizeof(struct snet_event), 0) % event_hash_size; >> + list_add_tail(&data->list, &event_hash[h]); >> + write_unlock_bh(&event_hash_lock); >> + >> + return 0; >> +} > >> +/* init function */ >> +int snet_event_init(void) >> +{ >> + int err = 0, i = 0; >> + >> + event_hash = kzalloc(sizeof(struct list_head) * event_hash_size, >> + GFP_KERNEL); >> + if (!event_hash) { >> + printk(KERN_WARNING >> + "snet: can't alloc memory for event_hash\n"); >> + err = -ENOMEM; >> + goto out; >> + } >> + >> + for (i = 0; i < event_hash_size; i++) >> + INIT_LIST_HEAD(&(event_hash[i])); > > No need for double braces. again fixed. thanks for your time Evgeniy, sam -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoting Samir Bellabes (sam@synack.fr): > This patch adds the snet's subsystem responsive of managing events > > snet is using the word 'event' for a couple of values [syscall, protocol]. For > example, [listen, tcp] or [sendmsg, dccp] are events. > This patch introduces a hastable 'event_hash' and operations (add/remove/search..) > in order to manage which events have to be protected. > With the help of the communication's subsystem, managing orders are coming from > userspace. > > Signed-off-by: Samir Bellabes <sam@synack.fr> > --- > security/snet/include/snet_event.h | 20 +++ > security/snet/snet_event.c | 229 ++++++++++++++++++++++++++++++++++++ > 2 files changed, 249 insertions(+), 0 deletions(-) > create mode 100644 security/snet/include/snet_event.h > create mode 100644 security/snet/snet_event.c > > diff --git a/security/snet/include/snet_event.h b/security/snet/include/snet_event.h > new file mode 100644 > index 0000000..2c71ca7 > --- /dev/null > +++ b/security/snet/include/snet_event.h > @@ -0,0 +1,20 @@ > +#ifndef _SNET_EVENT_H > +#define _SNET_EVENT_H > +#include <linux/skbuff.h> > + > +extern unsigned int event_hash_size; > + > +/* manipulate the events hash table */ > +int snet_event_fill_info(struct sk_buff *skb, struct netlink_callback *cb); > +int snet_event_is_registered(const enum snet_syscall syscall, const u8 protocol); > +int snet_event_insert(const enum snet_syscall syscall, const u8 protocol); > +int snet_event_remove(const enum snet_syscall syscall, const u8 protocol); > +void snet_event_flush(void); > +void snet_event_dumpall(void); > + > +/* init function */ > +int snet_event_init(void); > +/* exit funtion */ > +int snet_event_exit(void); > + > +#endif /* _SNET_EVENT_H */ > diff --git a/security/snet/snet_event.c b/security/snet/snet_event.c > new file mode 100644 > index 0000000..6ac5646 > --- /dev/null > +++ b/security/snet/snet_event.c > @@ -0,0 +1,229 @@ > +#include <linux/spinlock.h> > +#include <linux/list.h> > +#include <linux/jhash.h> > +#include <linux/slab.h> > +#include <linux/netlink.h> > + > +#include "snet.h" > +#include "snet_event.h" > +#include "snet_netlink.h" > + > +static struct list_head *event_hash; > +static rwlock_t event_hash_lock = __RW_LOCK_UNLOCKED(); > + > +struct snet_event_entry { > + struct list_head list; > + struct snet_event se; > +}; > + > +/* lookup for a event_hash - before using this function, lock event_hash_lock */ > +static struct snet_event_entry *__snet_event_lookup(const enum snet_syscall syscall, > + const u8 protocol) > +{ > + unsigned int h = 0; > + struct list_head *l; > + struct snet_event_entry *s; > + struct snet_event t; > + > + if (!event_hash) > + return NULL; > + > + /* building the element to look for */ > + t.syscall = syscall; > + t.protocol = protocol; > + > + /* computing its hash value */ > + h = jhash(&t, sizeof(struct snet_event), 0) % event_hash_size; > + l = &event_hash[h]; > + > + list_for_each_entry(s, l, list) { > + if ((s->se.protocol == protocol) && > + (s->se.syscall == syscall)) { > + return s; > + } > + } > + return NULL; > +} > + > +int snet_event_fill_info(struct sk_buff *skb, struct netlink_callback *cb) > +{ > + unsigned int i = 0, n = 0; > + int ret = -1; > + unsigned hashs_to_skip = cb->args[0]; > + unsigned events_to_skip = cb->args[1]; > + struct list_head *l; > + struct snet_event_entry *s; > + > + read_lock_bh(&event_hash_lock); > + > + if (!event_hash) > + goto errout; > + > + for (i = 0; i < event_hash_size; i++) { > + if (i < hashs_to_skip) > + continue; What is this? > + l = &event_hash[i]; > + n = 0; > + list_for_each_entry(s, l, list) { > + if (++n < events_to_skip) > + continue; > + ret = snet_nl_list_fill_info(skb, > + NETLINK_CB(cb->skb).pid, > + cb->nlh->nlmsg_seq, > + NLM_F_MULTI, > + s->se.protocol, > + s->se.syscall); > + if (ret < 0) > + goto errout; So if it returns 0, presumably meaning successfully handled, you want to go on processing any duplicates? > + } > + } > + > +errout: > + read_unlock_bh(&event_hash_lock); > + > + cb->args[0] = i; > + cb->args[1] = n; > + return skb->len; > +} > + > +/* void snet_event_dumpall() */ > +/* { */ > +/* unsigned int i = 0; */ > +/* struct list_head *l; */ > +/* struct snet_event_entry *s; */ > + > +/* snet_dbg("entering\n"); */ > +/* read_lock_bh(&event_hash_lock); */ > +/* for (i = 0; i < (event_hash_size - 1); i++) { */ > +/* l = &hash[i]; */ > +/* list_for_each_entry(s, l, list) { */ > +/* snet_dbg("[%d, %d, %d]\n", i, */ > +/* s->se.protocol, s->se.syscall); */ > +/* } */ > +/* } */ > +/* read_unlock_bh(&event_hash_lock); */ > +/* snet_dbg("exiting\n"); */ > +/* return; */ > +/* } */ > + > +/* > + * check if a event is registered or not > + * return 1 if event is registered, 0 if not > + */ > +int snet_event_is_registered(const enum snet_syscall syscall, const u8 protocol) > +{ > + int ret = 0; > + > + read_lock_bh(&event_hash_lock); > + if (__snet_event_lookup(syscall, protocol) != NULL) > + ret = 1; > + read_unlock_bh(&event_hash_lock); > + return ret; > +} > + > +/* adding a event */ > +int snet_event_insert(const enum snet_syscall syscall, const u8 protocol) > +{ > + struct snet_event_entry *data = NULL; > + unsigned int h = 0; > + > + data = kzalloc(sizeof(struct snet_event_entry), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + write_lock_bh(&event_hash_lock); > + /* check if event is already registered */ > + if (!event_hash || __snet_event_lookup(syscall, protocol) != NULL) { > + write_unlock_bh(&event_hash_lock); > + kfree(data); > + return -EINVAL; -EBUSY to help debugging? > + } > + > + data->se.syscall = syscall; > + data->se.protocol = protocol; > + INIT_LIST_HEAD(&(data->list)); > + h = jhash(&(data->se), sizeof(struct snet_event), 0) % event_hash_size; > + list_add_tail(&data->list, &event_hash[h]); > + write_unlock_bh(&event_hash_lock); > + > + return 0; > +} > + > +/* removing a event */ > +int snet_event_remove(const enum snet_syscall syscall, const u8 protocol) > +{ > + struct snet_event_entry *data = NULL; > + > + write_lock_bh(&event_hash_lock); > + data = __snet_event_lookup(syscall, protocol); > + if (data == NULL) { > + write_unlock_bh(&event_hash_lock); > + return -EINVAL; > + } > + > + list_del(&data->list); > + write_unlock_bh(&event_hash_lock); > + kfree(data); > + return 0; > +} > + > +/* flushing all events */ > +void __snet_event_flush(void) > +{ > + struct snet_event_entry *data = NULL; > + unsigned int i = 0; > + > + for (i = 0; i < event_hash_size; i++) { > + while (!list_empty(&event_hash[i])) { > + data = list_entry(event_hash[i].next, > + struct snet_event_entry, list); > + list_del(&data->list); > + kfree(data); > + } > + } > + return; > +} > + > +void snet_event_flush(void) > +{ > + write_lock_bh(&event_hash_lock); > + if (event_hash) > + __snet_event_flush(); > + write_unlock_bh(&event_hash_lock); > + return; > +} > + > +/* init function */ > +int snet_event_init(void) > +{ > + int err = 0, i = 0; > + > + event_hash = kzalloc(sizeof(struct list_head) * event_hash_size, > + GFP_KERNEL); > + if (!event_hash) { > + printk(KERN_WARNING > + "snet: can't alloc memory for event_hash\n"); > + err = -ENOMEM; > + goto out; > + } > + > + for (i = 0; i < event_hash_size; i++) > + INIT_LIST_HEAD(&(event_hash[i])); > + > +out: > + return err; > +} > + > +/* exit function */ > +int snet_event_exit(void) > +{ > + write_lock_bh(&event_hash_lock); > + if (event_hash) { > + __snet_event_flush(); > + kfree(event_hash); > + event_hash = NULL; > + } > + write_unlock_bh(&event_hash_lock); > + > + return 0; > +} > -- > 1.6.3.3 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-security-module" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
"Serge E. Hallyn" <serue@us.ibm.com> writes: > Quoting Samir Bellabes (sam@synack.fr): >> +int snet_event_fill_info(struct sk_buff *skb, struct netlink_callback *cb) >> +{ >> + unsigned int i = 0, n = 0; >> + int ret = -1; >> + unsigned hashs_to_skip = cb->args[0]; >> + unsigned events_to_skip = cb->args[1]; >> + struct list_head *l; >> + struct snet_event_entry *s; >> + >> + read_lock_bh(&event_hash_lock); >> + >> + if (!event_hash) >> + goto errout; >> + >> + for (i = 0; i < event_hash_size; i++) { >> + if (i < hashs_to_skip) >> + continue; > > What is this? code was duplicated from ctrl_dumpfamily() at net/netlink/genetlink.c this can be optimized by: for (i = hashs_to_skip; i < event_hash_size; i++) { I will made a patch for ctrl_dumpfamily() right now. >> + l = &event_hash[i]; >> + n = 0; >> + list_for_each_entry(s, l, list) { >> + if (++n < events_to_skip) >> + continue; >> + ret = snet_nl_list_fill_info(skb, >> + NETLINK_CB(cb->skb).pid, >> + cb->nlh->nlmsg_seq, >> + NLM_F_MULTI, >> + s->se.protocol, >> + s->se.syscall); >> + if (ret < 0) >> + goto errout; > > So if it returns 0, presumably meaning successfully handled, you > want to go on processing any duplicates? first, I found a bug in snet_nl_list_fill_info() which was returning 0 instead of -EMSGSIZE in case there was not enough space to put data. I'm not sure to understand what may have duplicates, but if you are talking about the events (struct snet_event_entry), that is not possible as the insert function checks if the event is already in the hashtable snet_evh before insertion. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoting Samir Bellabes (sam@synack.fr): > "Serge E. Hallyn" <serue@us.ibm.com> writes: > > > Quoting Samir Bellabes (sam@synack.fr): > >> +int snet_event_fill_info(struct sk_buff *skb, struct netlink_callback *cb) > >> +{ > >> + unsigned int i = 0, n = 0; > >> + int ret = -1; > >> + unsigned hashs_to_skip = cb->args[0]; > >> + unsigned events_to_skip = cb->args[1]; > >> + struct list_head *l; > >> + struct snet_event_entry *s; > >> + > >> + read_lock_bh(&event_hash_lock); > >> + > >> + if (!event_hash) > >> + goto errout; > >> + > >> + for (i = 0; i < event_hash_size; i++) { > >> + if (i < hashs_to_skip) > >> + continue; > > > > What is this? > > code was duplicated from ctrl_dumpfamily() at net/netlink/genetlink.c > this can be optimized by: > for (i = hashs_to_skip; i < event_hash_size; i++) { Sure, but my question was more general (more naive?) - what are the hashs_to_skip? sounds like i should be able to go read the genetlink code for an answer, thanks. > I will made a patch for ctrl_dumpfamily() right now. > > >> + l = &event_hash[i]; > >> + n = 0; > >> + list_for_each_entry(s, l, list) { > >> + if (++n < events_to_skip) > >> + continue; > >> + ret = snet_nl_list_fill_info(skb, > >> + NETLINK_CB(cb->skb).pid, > >> + cb->nlh->nlmsg_seq, > >> + NLM_F_MULTI, > >> + s->se.protocol, > >> + s->se.syscall); > >> + if (ret < 0) > >> + goto errout; > > > > So if it returns 0, presumably meaning successfully handled, you > > want to go on processing any duplicates? > > first, I found a bug in snet_nl_list_fill_info() which was returning 0 > instead of -EMSGSIZE in case there was not enough space to put data. > > I'm not sure to understand what may have duplicates, but if you are > talking about the events (struct snet_event_entry), that is not possible > as the insert function checks if the event is already in the hashtable > snet_evh before insertion. Ok, but the way your loop is constructed, if snet_nl_list_fill_info() returns 0 (success, presumably) you won't break. Sounds like you want to. -serge -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
"Serge E. Hallyn" <serue@us.ibm.com> writes: > Quoting Samir Bellabes (sam@synack.fr): >> "Serge E. Hallyn" <serue@us.ibm.com> writes: >> >> > Quoting Samir Bellabes (sam@synack.fr): >> >> +int snet_event_fill_info(struct sk_buff *skb, struct netlink_callback *cb) >> >> +{ >> >> + unsigned int i = 0, n = 0; >> >> + int ret = -1; >> >> + unsigned hashs_to_skip = cb->args[0]; >> >> + unsigned events_to_skip = cb->args[1]; >> >> + struct list_head *l; >> >> + struct snet_event_entry *s; >> >> + >> >> + read_lock_bh(&event_hash_lock); >> >> + >> >> + if (!event_hash) >> >> + goto errout; >> >> + >> >> + for (i = 0; i < event_hash_size; i++) { >> >> + if (i < hashs_to_skip) >> >> + continue; >> > >> > What is this? >> >> code was duplicated from ctrl_dumpfamily() at net/netlink/genetlink.c >> this can be optimized by: >> for (i = hashs_to_skip; i < event_hash_size; i++) { > > Sure, but my question was more general (more naive?) - what are the > hashs_to_skip? > > sounds like i should be able to go read the genetlink code for an > answer, thanks. if it's not too late. snet_nl_list(), in snet_netlink.c, is defined as a dumpit() genetlink operation. A dumpit() operations is called when NLM_DUMP message flag is set. the genetlink dumpit() operation receives, as a argument, a pre-allocated sk_buff buffer, so the purpose of snet_nl_list() is to fill this buffer. snet_nl_list() is calling snet_event_fill_info() for this job. as long as snet_event_fill_info() is not returning 0, it means that it fills data in the sk_buff, and the dumpit() operations is called again. the behaviour of sending event list informations is to send a netlink message by event - remember a event is [syscall, protocol]. so we are iterate other the hashtable snet_evh: [0] -> list_head: [sys0, proto1], [sys1, proto1] [1] -> list_head: .. [2] -> list_head: .. ... [snet_evh_size-1] -> list_head: .. in order to fill each the pre-allocated sk_buff. so at each time the snet_event_fill_info() is called again, because of returning values different from 0, we need to skip previous events which were already filled in the buffer. this is the purpose of unsigned hashs_to_skip = cb->args[0]; unsigned events_to_skip = cb->args[1]; to get the last event filled, and the purpose of : cb->args[0] = i; cb->args[1] = n; to store the last event filled, at each call of dumpit() at this point you may understand the purpose to skip the previous values in the hashtables, and after the events values at each list. >> I will made a patch for ctrl_dumpfamily() right now. >> >> >> + l = &event_hash[i]; >> >> + n = 0; >> >> + list_for_each_entry(s, l, list) { >> >> + if (++n < events_to_skip) >> >> + continue; >> >> + ret = snet_nl_list_fill_info(skb, >> >> + NETLINK_CB(cb->skb).pid, >> >> + cb->nlh->nlmsg_seq, >> >> + NLM_F_MULTI, >> >> + s->se.protocol, >> >> + s->se.syscall); >> >> + if (ret < 0) >> >> + goto errout; >> > >> > So if it returns 0, presumably meaning successfully handled, you >> > want to go on processing any duplicates? >> >> first, I found a bug in snet_nl_list_fill_info() which was returning 0 >> instead of -EMSGSIZE in case there was not enough space to put data. >> >> I'm not sure to understand what may have duplicates, but if you are >> talking about the events (struct snet_event_entry), that is not possible >> as the insert function checks if the event is already in the hashtable >> snet_evh before insertion. > > Ok, but the way your loop is constructed, if snet_nl_list_fill_info() > returns 0 (success, presumably) you won't break. Sounds like you want > to. No I don't, if it returns 0, we proceed the next event in the current list. once the list is empty, we proceed the next hashtable entry. once the index running other the hashtable is egal to the hashtable size, it's done. sam -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Samir Bellabes <sam@synack.fr> writes: > No I don't, if it returns 0, we proceed the next event in the current > list. To be sure you shall understand: No I don't want to break. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoting Samir Bellabes (sam@synack.fr): > Samir Bellabes <sam@synack.fr> writes: > > > > No I don't, if it returns 0, we proceed the next event in the current > > list. > > To be sure you shall understand: No I don't want to break. Thanks :) -serge -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/security/snet/include/snet_event.h b/security/snet/include/snet_event.h new file mode 100644 index 0000000..2c71ca7 --- /dev/null +++ b/security/snet/include/snet_event.h @@ -0,0 +1,20 @@ +#ifndef _SNET_EVENT_H +#define _SNET_EVENT_H +#include <linux/skbuff.h> + +extern unsigned int event_hash_size; + +/* manipulate the events hash table */ +int snet_event_fill_info(struct sk_buff *skb, struct netlink_callback *cb); +int snet_event_is_registered(const enum snet_syscall syscall, const u8 protocol); +int snet_event_insert(const enum snet_syscall syscall, const u8 protocol); +int snet_event_remove(const enum snet_syscall syscall, const u8 protocol); +void snet_event_flush(void); +void snet_event_dumpall(void); + +/* init function */ +int snet_event_init(void); +/* exit funtion */ +int snet_event_exit(void); + +#endif /* _SNET_EVENT_H */ diff --git a/security/snet/snet_event.c b/security/snet/snet_event.c new file mode 100644 index 0000000..6ac5646 --- /dev/null +++ b/security/snet/snet_event.c @@ -0,0 +1,229 @@ +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/jhash.h> +#include <linux/slab.h> +#include <linux/netlink.h> + +#include "snet.h" +#include "snet_event.h" +#include "snet_netlink.h" + +static struct list_head *event_hash; +static rwlock_t event_hash_lock = __RW_LOCK_UNLOCKED(); + +struct snet_event_entry { + struct list_head list; + struct snet_event se; +}; + +/* lookup for a event_hash - before using this function, lock event_hash_lock */ +static struct snet_event_entry *__snet_event_lookup(const enum snet_syscall syscall, + const u8 protocol) +{ + unsigned int h = 0; + struct list_head *l; + struct snet_event_entry *s; + struct snet_event t; + + if (!event_hash) + return NULL; + + /* building the element to look for */ + t.syscall = syscall; + t.protocol = protocol; + + /* computing its hash value */ + h = jhash(&t, sizeof(struct snet_event), 0) % event_hash_size; + l = &event_hash[h]; + + list_for_each_entry(s, l, list) { + if ((s->se.protocol == protocol) && + (s->se.syscall == syscall)) { + return s; + } + } + return NULL; +} + +int snet_event_fill_info(struct sk_buff *skb, struct netlink_callback *cb) +{ + unsigned int i = 0, n = 0; + int ret = -1; + unsigned hashs_to_skip = cb->args[0]; + unsigned events_to_skip = cb->args[1]; + struct list_head *l; + struct snet_event_entry *s; + + read_lock_bh(&event_hash_lock); + + if (!event_hash) + goto errout; + + for (i = 0; i < event_hash_size; i++) { + if (i < hashs_to_skip) + continue; + l = &event_hash[i]; + n = 0; + list_for_each_entry(s, l, list) { + if (++n < events_to_skip) + continue; + ret = snet_nl_list_fill_info(skb, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, + NLM_F_MULTI, + s->se.protocol, + s->se.syscall); + if (ret < 0) + goto errout; + } + } + +errout: + read_unlock_bh(&event_hash_lock); + + cb->args[0] = i; + cb->args[1] = n; + return skb->len; +} + +/* void snet_event_dumpall() */ +/* { */ +/* unsigned int i = 0; */ +/* struct list_head *l; */ +/* struct snet_event_entry *s; */ + +/* snet_dbg("entering\n"); */ +/* read_lock_bh(&event_hash_lock); */ +/* for (i = 0; i < (event_hash_size - 1); i++) { */ +/* l = &hash[i]; */ +/* list_for_each_entry(s, l, list) { */ +/* snet_dbg("[%d, %d, %d]\n", i, */ +/* s->se.protocol, s->se.syscall); */ +/* } */ +/* } */ +/* read_unlock_bh(&event_hash_lock); */ +/* snet_dbg("exiting\n"); */ +/* return; */ +/* } */ + +/* + * check if a event is registered or not + * return 1 if event is registered, 0 if not + */ +int snet_event_is_registered(const enum snet_syscall syscall, const u8 protocol) +{ + int ret = 0; + + read_lock_bh(&event_hash_lock); + if (__snet_event_lookup(syscall, protocol) != NULL) + ret = 1; + read_unlock_bh(&event_hash_lock); + return ret; +} + +/* adding a event */ +int snet_event_insert(const enum snet_syscall syscall, const u8 protocol) +{ + struct snet_event_entry *data = NULL; + unsigned int h = 0; + + data = kzalloc(sizeof(struct snet_event_entry), GFP_KERNEL); + if (!data) + return -ENOMEM; + + write_lock_bh(&event_hash_lock); + /* check if event is already registered */ + if (!event_hash || __snet_event_lookup(syscall, protocol) != NULL) { + write_unlock_bh(&event_hash_lock); + kfree(data); + return -EINVAL; + } + + data->se.syscall = syscall; + data->se.protocol = protocol; + INIT_LIST_HEAD(&(data->list)); + h = jhash(&(data->se), sizeof(struct snet_event), 0) % event_hash_size; + list_add_tail(&data->list, &event_hash[h]); + write_unlock_bh(&event_hash_lock); + + return 0; +} + +/* removing a event */ +int snet_event_remove(const enum snet_syscall syscall, const u8 protocol) +{ + struct snet_event_entry *data = NULL; + + write_lock_bh(&event_hash_lock); + data = __snet_event_lookup(syscall, protocol); + if (data == NULL) { + write_unlock_bh(&event_hash_lock); + return -EINVAL; + } + + list_del(&data->list); + write_unlock_bh(&event_hash_lock); + kfree(data); + return 0; +} + +/* flushing all events */ +void __snet_event_flush(void) +{ + struct snet_event_entry *data = NULL; + unsigned int i = 0; + + for (i = 0; i < event_hash_size; i++) { + while (!list_empty(&event_hash[i])) { + data = list_entry(event_hash[i].next, + struct snet_event_entry, list); + list_del(&data->list); + kfree(data); + } + } + return; +} + +void snet_event_flush(void) +{ + write_lock_bh(&event_hash_lock); + if (event_hash) + __snet_event_flush(); + write_unlock_bh(&event_hash_lock); + return; +} + +/* init function */ +int snet_event_init(void) +{ + int err = 0, i = 0; + + event_hash = kzalloc(sizeof(struct list_head) * event_hash_size, + GFP_KERNEL); + if (!event_hash) { + printk(KERN_WARNING + "snet: can't alloc memory for event_hash\n"); + err = -ENOMEM; + goto out; + } + + for (i = 0; i < event_hash_size; i++) + INIT_LIST_HEAD(&(event_hash[i])); + +out: + return err; +} + +/* exit function */ +int snet_event_exit(void) +{ + write_lock_bh(&event_hash_lock); + if (event_hash) { + __snet_event_flush(); + kfree(event_hash); + event_hash = NULL; + } + write_unlock_bh(&event_hash_lock); + + return 0; +}
This patch adds the snet's subsystem responsive of managing events snet is using the word 'event' for a couple of values [syscall, protocol]. For example, [listen, tcp] or [sendmsg, dccp] are events. This patch introduces a hastable 'event_hash' and operations (add/remove/search..) in order to manage which events have to be protected. With the help of the communication's subsystem, managing orders are coming from userspace. Signed-off-by: Samir Bellabes <sam@synack.fr> --- security/snet/include/snet_event.h | 20 +++ security/snet/snet_event.c | 229 ++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+), 0 deletions(-) create mode 100644 security/snet/include/snet_event.h create mode 100644 security/snet/snet_event.c