Netdev List
 help / color / mirror / Atom feed
* RE: [PATCH] Export smbios strings associated with onboard devicesto sysfs
From: Narendra_K @ 2010-03-02 17:42 UTC (permalink / raw)
  To: achiang
  Cc: netdev, linux-hotplug, linux-pci, Matt_Domsch, Jordan_Hargrave,
	Sandeep_K_Shandilya, Charles_Rose, Shyam_Iyer
In-Reply-To: <20100225214020.GA15010@ldl.fc.hp.com>

> -----Original Message-----
> From: Alex Chiang [mailto:achiang@hp.com]
> Sent: Friday, February 26, 2010 3:10 AM
> To: K, Narendra
> Cc: netdev@vger.kernel.org; linux-hotplug@vger.kernel.org; linux-
> pci@vger.kernel.org; Domsch, Matt; Hargrave, Jordan; Shandilya,
Sandeep
> K; Rose, Charles; Iyer, Shyam
> Subject: Re: [PATCH] Export smbios strings associated with onboard
> devicesto sysfs
> 
> * Narendra K <Narendra_K@dell.com>:
> >
> > * We have been having discussions in the netdev list about
> > creating multiple names for the network interfaces to bring
> > determinism into the way network interfaces are named in the
> > OSes. In specific, "eth0 in the OS does not always map to the
> > integrated NIC Gb1 as labelled on the chassis".
> 
> Yes, I agree that this is a real problem that we do not handle
> well today.
> 
> > 1.Export smbios strings of onboard devices, to sysfs. For example -
> >
> > cat /sys/class/net/eth0/device/smbiosname
> > Embedded NIC 2
> >
> > cat  /sys/bus/pci/devices/0000\:03\:00.0/smbiosname
> > Embedded NIC 2
> 
> I agree with this concept, but I don't like the interface.
> 
> The name "smbiosname" isn't the proper level of abstraction. We
> don't want users to care what firmware standard is providing the
> name (think smbios vs acpi vs open firmware...).
> 
> We learned this lesson with exposing ACPI interfaces. Let's not
> make the same mistake here.
> 
> Something like "firmwarename", "fwname", "platformname" etc. is
> generic, and then the interface will make sense for platforms
> that do not implement SMBIOS.
> 
> I don't particularly care which name you choose as long as it's
> properly generic.
> 
> As far as implementation goes, I've been thinking about this
> problem for a while now, and I keep wanting to use the
> pci_create_slot() API, but am still a little on the fence about
> it.
> 
> The pros:
> 	- all you have to do is write a simple little driver that
> 	  can read SMBIOS to get PCI bus:devfn and the name, and
> 	  then you call pci_create_slot(). Then you get all sorts
> 	  of stuff for free, like sysfs exposure, proper
> 	  refcounting (important given that the PCI logical
> 	  hotplug interface (/sys/bus/pci/rescan and friends) can
> 	  be used to remove onboard devices), etc.
> 
> 	- see drivers/acpi/pci_slot.c for an example of how to
> 	  detect slots and then register them.
> 
> The cons:
> 	- the user interface is /sys/bus/pci/slots/<name>
> 
> 	I don't know if that is an appropriate interface, since
> 	technically an onboard device isn't in a slot. But maybe
> 	if you did something like:
> 
> 		/sys/bus/pci/slots/onboard0
> 		/sys/bus/pci/slots/onboard1
> 
> 	that might make sense.
> 
> 	Or...
> 		/sys/bus/pci/onboard/<name>
> 
> I read through the patch, but given that the implementation
> strategy might change based on my comments, will hold off and see
> how the conversation develops.

Thanks. I will wait too, to see how the discussion develops on this
method of implementation.

With regards,
Narendra K

^ permalink raw reply

* e1000e: reset of tx_queue_len
From: Franco Fichtner @ 2010-03-02 17:44 UTC (permalink / raw)
  To: Netdev, jesse.brandeburg, bruce.w.allan

Hi all,

while working on a new server, I noticed that tx_queue_len is reset
to the default of 1000 while ADDRCONF(NETDEV_CHANGE).
This happens with 2.6.30.8, but I could not see any obvious
differences to the current state of e1000e, while trying to find the
problem in the code.

The interface has been configured including a customized qlen
via /etc/network/interfaces. The ports are not connected at startup
so obviously the Kernel reports

ADDRCONF(NETDEV_UP): eth2: link is not ready

while ifconfig properly displays the customized qlen.

When plugging the server tx_queue_len is reset to 1000.

Any help is appreciated. Thanks.


Franco

^ permalink raw reply

* [PATCH]  bridge: per-cpu packet statistics (v2)
From: Stephen Hemminger @ 2010-03-02 17:58 UTC (permalink / raw)
  To: David Miller; +Cc: Eric Dumazet, netdev, bridge
In-Reply-To: <1267520579.2964.27.camel@edumazet-laptop>

The shared packet statistics are a potential source of slow down
on bridged traffic. Convert to per-cpu array, but only keep those
statistics which change per-packet.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

---
Take Eric's bug fix changes. But keep the per cpu transmit
per cpu statistics.  There is no point in going multiqueue for
a pseudo-interface which is lockless and queue less.

 net/bridge/br_device.c  |   43 ++++++++++++++++++++++++++++++++++++++-----
 net/bridge/br_if.c      |    6 ++++++
 net/bridge/br_input.c   |    5 +++--
 net/bridge/br_private.h |    8 ++++++++
 4 files changed, 55 insertions(+), 7 deletions(-)

--- a/net/bridge/br_device.c	2010-03-02 09:26:23.208191713 -0800
+++ b/net/bridge/br_device.c	2010-03-02 09:29:38.811818410 -0800
@@ -26,11 +26,12 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
 	const unsigned char *dest = skb->data;
 	struct net_bridge_fdb_entry *dst;
 	struct net_bridge_mdb_entry *mdst;
+	struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
-	BR_INPUT_SKB_CB(skb)->brdev = dev;
+	brstats->tx_packets++;
+	brstats->tx_bytes += skb->len;
 
-	dev->stats.tx_packets++;
-	dev->stats.tx_bytes += skb->len;
+	BR_INPUT_SKB_CB(skb)->brdev = dev;
 
 	skb_reset_mac_header(skb);
 	skb_pull(skb, ETH_HLEN);
@@ -81,6 +82,31 @@ static int br_dev_stop(struct net_device
 	return 0;
 }
 
+static struct net_device_stats *br_get_stats(struct net_device *dev)
+{
+	struct net_bridge *br = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	struct br_cpu_netstats sum = { 0 };
+	unsigned int cpu;
+
+	for_each_possible_cpu(cpu) {
+		const struct br_cpu_netstats *bstats
+			= per_cpu_ptr(br->stats, cpu);
+
+		sum.tx_bytes   += bstats->tx_bytes;
+		sum.tx_packets += bstats->tx_packets;
+		sum.rx_bytes   += bstats->rx_bytes;
+		sum.rx_packets += bstats->rx_packets;
+	}
+
+	stats->tx_bytes   = sum.tx_bytes;
+	stats->tx_packets = sum.tx_packets;
+	stats->rx_bytes   = sum.rx_bytes;
+	stats->rx_packets = sum.rx_packets;
+
+	return stats;
+}
+
 static int br_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct net_bridge *br = netdev_priv(dev);
@@ -180,19 +206,28 @@ static const struct net_device_ops br_ne
 	.ndo_open		 = br_dev_open,
 	.ndo_stop		 = br_dev_stop,
 	.ndo_start_xmit		 = br_dev_xmit,
+	.ndo_get_stats		 = br_get_stats,
 	.ndo_set_mac_address	 = br_set_mac_address,
 	.ndo_set_multicast_list	 = br_dev_set_multicast_list,
 	.ndo_change_mtu		 = br_change_mtu,
 	.ndo_do_ioctl		 = br_dev_ioctl,
 };
 
+static void br_dev_free(struct net_device *dev)
+{
+	struct net_bridge *br = netdev_priv(dev);
+
+	free_percpu(br->stats);
+	free_netdev(dev);
+}
+
 void br_dev_setup(struct net_device *dev)
 {
 	random_ether_addr(dev->dev_addr);
 	ether_setup(dev);
 
 	dev->netdev_ops = &br_netdev_ops;
-	dev->destructor = free_netdev;
+	dev->destructor = br_dev_free;
 	SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
 	dev->tx_queue_len = 0;
 	dev->priv_flags = IFF_EBRIDGE;
--- a/net/bridge/br_if.c	2010-03-02 09:26:23.188192219 -0800
+++ b/net/bridge/br_if.c	2010-03-02 09:31:19.801199305 -0800
@@ -185,6 +185,12 @@ static struct net_device *new_bridge_dev
 	br = netdev_priv(dev);
 	br->dev = dev;
 
+	br->stats = alloc_percpu(struct br_cpu_netstats);
+	if (!br->stats) {
+		free_netdev(dev);
+		return NULL;
+	}
+
 	spin_lock_init(&br->lock);
 	INIT_LIST_HEAD(&br->port_list);
 	spin_lock_init(&br->hash_lock);
--- a/net/bridge/br_input.c	2010-03-02 09:26:23.196192436 -0800
+++ b/net/bridge/br_input.c	2010-03-02 09:27:04.424067504 -0800
@@ -23,9 +23,11 @@ const u8 br_group_address[ETH_ALEN] = { 
 static int br_pass_frame_up(struct sk_buff *skb)
 {
 	struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
+	struct net_bridge *br = netdev_priv(brdev);
+	struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
-	brdev->stats.rx_packets++;
-	brdev->stats.rx_bytes += skb->len;
+	brstats->rx_packets++;
+	brstats->rx_bytes += skb->len;
 
 	indev = skb->dev;
 	skb->dev = brdev;
--- a/net/bridge/br_private.h	2010-03-02 09:26:23.180193181 -0800
+++ b/net/bridge/br_private.h	2010-03-02 09:27:04.424067504 -0800
@@ -135,6 +135,14 @@ struct net_bridge
 	spinlock_t			lock;
 	struct list_head		port_list;
 	struct net_device		*dev;
+
+	struct br_cpu_netstats __percpu {
+		unsigned long	rx_packets;
+		unsigned long	tx_packets;
+		unsigned long	rx_bytes;
+		unsigned long	tx_bytes;
+	} *stats;
+
 	spinlock_t			hash_lock;
 	struct hlist_head		hash[BR_HASH_SIZE];
 	unsigned long			feature_mask;

^ permalink raw reply

* Re: [PATCH]  bridge: per-cpu packet statistics (v2)
From: Eric Dumazet @ 2010-03-02 18:06 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Miller, netdev, bridge
In-Reply-To: <20100302095831.151c8bb5@nehalam>

Le mardi 02 mars 2010 à 09:58 -0800, Stephen Hemminger a écrit :
> +	struct br_cpu_netstats __percpu {
> +		unsigned long	rx_packets;
> +		unsigned long	tx_packets;
> +		unsigned long	rx_bytes;
> +		unsigned long	tx_bytes;
> +	} *stats;
> +

Ok, please group rx stats together instead of interleave, this to reduce
possibility of touching two cache lines in tx path (or rx path)

	struct br_cpu_netstats __percpu {
> 		unsigned long	rx_packets;
> +		unsigned long	rx_bytes;
> 
> +		unsigned long	tx_packets;
> +		unsigned long	tx_bytes;
> +	} *stats;
> +



^ permalink raw reply

* Re: e1000e: reset of tx_queue_len
From: Brandeburg, Jesse @ 2010-03-02 18:27 UTC (permalink / raw)
  To: Franco Fichtner; +Cc: Netdev, Allan, Bruce W
In-Reply-To: <4B8D4E7E.2000805@lastsummer.de>



On Tue, 2 Mar 2010, Franco Fichtner wrote:
> while working on a new server, I noticed that tx_queue_len is reset
> to the default of 1000 while ADDRCONF(NETDEV_CHANGE).
> This happens with 2.6.30.8, but I could not see any obvious
> differences to the current state of e1000e, while trying to find the
> problem in the code.

The driver tries to set the queuelen back to 1000 if the link changes 
speed, because the driver tries to shorten the txqueuelen to 100 to reduce 
latency when the link changes to 100/10 Mb/s

> The interface has been configured including a customized qlen
> via /etc/network/interfaces. The ports are not connected at startup
> so obviously the Kernel reports
> 
> ADDRCONF(NETDEV_UP): eth2: link is not ready

do your scripts try to configure the queuelen when link is not up?  Why 
are the ports not connected at startup?

> 
> while ifconfig properly displays the customized qlen.
> 
> When plugging the server tx_queue_len is reset to 1000.
> 
> Any help is appreciated. Thanks.

you can safely comment out the code in netdev.c on lines 3532 through 
3549, as well as any other lines of code in the driver that modify or use 
the variable netdev->tx_queue_len

http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.30.y.git;a=blob;f=drivers/net/e1000e/netdev.c;h=42055a580f7ccd6cc2ac59ea5d7d864157b57107;hb=HEAD#l3532

Its possible we should just remove this code from the in-kernel 
driver, as I don't think many other drivers mess with the tx_queue_len 
either.  We did introduce the code to fix some users complaints about the 
amount of work that can get queued up in the hardware with tx_queue_len = 
1000 when at 10/100 speeds.

Hope this helps!

^ permalink raw reply

* Re: [PATCH] Export smbios strings associated with onboard devices to sysfs
From: Greg KH @ 2010-03-02 18:28 UTC (permalink / raw)
  To: Narendra K
  Cc: matt_domsch, netdev, linux-hotplug, linux-pci, jordan_hargrave,
	sandeep_k_shandilya, charles_rose, shyam_iyer
In-Reply-To: <20100302173302.GA20936@mock.linuxdev.us.dell.com>

On Tue, Mar 02, 2010 at 11:33:04AM -0600, Narendra K wrote:
> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
> index 807224e..85d5d79 100644
> --- a/drivers/pci/pci-sysfs.c
> +++ b/drivers/pci/pci-sysfs.c
> @@ -142,6 +142,54 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
>  		       (u8)(pci_dev->class));
>  }
>  
> +#ifdef CONFIG_DMI
> +#include <linux/dmi.h>

#includes go at the top of the file.

Can you just create a pci-dmi.c and put this in that .c that way you
don't need any #ifdefs in a .c file?

> +static ssize_t
> +smbiosname_string_is_valid(struct device *dev, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +  	struct dmi_device *dmi;
> +  	struct dmi_devslot *dslot;
> +  	int bus;
> +  	int devfn;
> +
> +  	bus = pdev->bus->number;
> +  	devfn = pdev->devfn;
> +
> +  	dmi = NULL;
> +  	while ((dmi = dmi_find_device(DMI_DEV_TYPE_DEVSLOT, NULL, dmi)) != NULL) {
> +    		dslot = dmi->device_data;
> +    		if (dslot && dslot->bus == bus && dslot->devfn == devfn) {
> +			if (buf)
> +      				return scnprintf(buf, PAGE_SIZE, "%s\n", dmi->name);
> +			return strlen(dmi->name);
> +		}
> +	}
> +}
> +
> +static ssize_t
> +smbiosname_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	return smbiosname_string_is_valid(dev, buf);
> +
> +}
> +
> +struct smbios_attribute {
> +	struct attribute attr;
> +	ssize_t(*show) (struct device * edev, char *buf);
> +	int (*test) (struct device * edev, char *buf);
> +};

Why are you creating your own attribute type?

> +
> +#define SMBIOSNAME_DEVICE_ATTR(_name, _mode, _show, _test) \
> +struct smbios_attribute smbios_attr_##_name = { 	\
> +	.attr = {.name = __stringify(_name), .mode = _mode },	\
> +	.show	= _show,				\
> +	.test	= _test,				\
> +};
> +
> +static SMBIOSNAME_DEVICE_ATTR(smbiosname, 0444, smbiosname_show, smbiosname_string_is_valid);

Why are you creating a #define that is only used once?

What is wrong with a "normal" device attribute that you can not use it
here?

> +#endif
> +
>  static ssize_t is_enabled_store(struct device *dev,
>  				struct device_attribute *attr, const char *buf,
>  				size_t count)
> @@ -1140,6 +1188,7 @@ static int __init pci_sysfs_init(void)
>  {
>  	struct pci_dev *pdev = NULL;
>  	int retval;
> +	struct smbios_attribute *attr = &smbios_attr_smbiosname;
>  
>  	sysfs_initialized = 1;
>  	for_each_pci_dev(pdev) {
> @@ -1148,6 +1197,11 @@ static int __init pci_sysfs_init(void)
>  			pci_dev_put(pdev);
>  			return retval;
>  		}
> +#ifdef CONFIG_DMI
> +		/* if the device does not have an associated smbios string in the smbios table, do not create this attribute */ 
> +		if (attr->test && attr->test(&pdev->dev, NULL))
> +			sysfs_create_file(&pdev->dev.kobj, &attr->attr);
> +#endif

Put this in a new function and call it in a different file.

And how are you handling pci devices that are added after the pci
subsystem is initialized (think pci hotplug).

And where are you removing this sysfs file?

Why not put this in the pci_create_sysfs_dev_files function?

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH]: tipc: Fix oops on send prior to entering networked mode (v2)
From: Neil Horman @ 2010-03-02 18:33 UTC (permalink / raw)
  To: netdev; +Cc: jon.maloy, allan.stephens, tipc-discussion, davem
In-Reply-To: <20100219194033.GA28743@hmsreliant.think-freely.org>

Ok, after some debate, heres version 2 of this patch.  Its a complete rewrite.
I started with the patches we'd proposed previously, then realized theres a much
easier and elegant way to handle this, which I've implemented below.

Fix TIPC to disallow sending to remote addresses prior to entering NET_MODE

user programs can oops the kernel by sending datagrams via AF_TIPC prior to
entering networked mode.  The following backtrace has been observed:

ID: 13459  TASK: ffff810014640040  CPU: 0   COMMAND: "tipc-client"
[exception RIP: tipc_node_select_next_hop+90]
RIP: ffffffff8869d3c3  RSP: ffff81002d9a5ab8  RFLAGS: 00010202
RAX: 0000000000000001  RBX: 0000000000000001  RCX: 0000000000000001
RDX: 0000000000000000  RSI: 0000000000000001  RDI: 0000000001001001
RBP: 0000000001001001   R8: 0074736575716552   R9: 0000000000000000
R10: ffff81003fbd0680  R11: 00000000000000c8  R12: 0000000000000008
R13: 0000000000000001  R14: 0000000000000001  R15: ffff810015c6ca00
ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
#4 [ffff81002d9a5ab0] tipc_node_select_next_hop at ffffffff8869d3b1
#5 [ffff81002d9a5ae0] tipc_link_send_sections_fast at ffffffff88698558
#6 [ffff81002d9a5be0] tipc_forward2port at ffffffff8869eb1d
#7 [ffff81002d9a5c10] tipc_send2port at ffffffff8869eb79
#8 [ffff81002d9a5c30] send_msg at ffffffff886a1d0b
#9 [ffff81002d9a5cb0] sock_sendmsg at ffffffff80055261
RIP: 0000003cbd8d49a3  RSP: 00007fffc84e0be8  RFLAGS: 00010206
RAX: 000000000000002c  RBX: ffffffff8005d116  RCX: 0000000000000000
RDX: 0000000000000008  RSI: 00007fffc84e0c00  RDI: 0000000000000003
RBP: 0000000000000000   R8: 00007fffc84e0c10   R9: 0000000000000010
R10: 0000000000000000  R11: 0000000000000246  R12: 0000000000000000
R13: 00007fffc84e0d10  R14: 0000000000000000  R15: 00007fffc84e0c30
ORIG_RAX: 000000000000002c  CS: 0033  SS: 002b

What happens is that, when the tipc module in inserted it enters a standalone
node mode in which communication to its own address is allowed <0.0.0> but not
to other addresses, since the appropriate data structures have not been
allocated yet (specifically the tipc_net pointer).  There is nothing stopping a
client from trying to send such a message however, and if that happens, we
attempt to dereference tipc_net.zones while the pointer is still NULL, and
explode.  The fix is pretty straightforward.  Since these oopses all arise from
the dereference of global pointers prior to their assignment to allocated
values, and since these allocations are small (about 2k total), lets convert
these pointers to static arrays of the appropriate size.  All the accesses to
these bits consider 0/NULL to be a non match when searching, so all the lookups
still work properly, and there is no longer a chance of a bad dererence
anywhere.  As a bonus, this lets us eliminate the setup/teardown routines for
those pointers, and elimnates the need to preform any locking around them to
prevent access while their being allocated/freed.

I've updated the tipc_net structure to behave this way to fix the exact reported
problem, and also fixed up the tipc_bearers and media_list arrays to fix an
obvious simmilar problem that arises from issuing tipc-config commands to
manipulate bearers/links prior to entering networked mode

I've tested this for a few hours by running the sanity tests and stress test
with the tipcutils suite, and nothing has fallen over.  There have been a few
lockdep warnings, but those were there before, and can be addressed later, as
they didn't actually result in any deadlock.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Allan Stephens <allan.stephens@windriver.com>
CC: David S. Miller <davem@davemloft.net>
CC: tipc-discussion@lists.sourceforge.net


 bearer.c |   28 ++--------------------------
 bearer.h |    2 +-
 net.c    |   25 ++++---------------------
 3 files changed, 7 insertions(+), 48 deletions(-)

diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 327011f..d1b9226 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -45,10 +45,10 @@
 
 #define MAX_ADDR_STR 32
 
-static struct media *media_list = NULL;
+static struct media media_list[MAX_MEDIA];
 static u32 media_count = 0;
 
-struct bearer *tipc_bearers = NULL;
+struct bearer tipc_bearers[MAX_BEARERS];
 
 /**
  * media_name_valid - validate media name
@@ -660,26 +660,6 @@ int tipc_disable_bearer(const char *name)
 
 
 
-int tipc_bearer_init(void)
-{
-	int res;
-
-	write_lock_bh(&tipc_net_lock);
-	tipc_bearers = kcalloc(MAX_BEARERS, sizeof(struct bearer), GFP_ATOMIC);
-	media_list = kcalloc(MAX_MEDIA, sizeof(struct media), GFP_ATOMIC);
-	if (tipc_bearers && media_list) {
-		res = 0;
-	} else {
-		kfree(tipc_bearers);
-		kfree(media_list);
-		tipc_bearers = NULL;
-		media_list = NULL;
-		res = -ENOMEM;
-	}
-	write_unlock_bh(&tipc_net_lock);
-	return res;
-}
-
 void tipc_bearer_stop(void)
 {
 	u32 i;
@@ -695,10 +675,6 @@ void tipc_bearer_stop(void)
 		if (tipc_bearers[i].active)
 			bearer_disable(tipc_bearers[i].publ.name);
 	}
-	kfree(tipc_bearers);
-	kfree(media_list);
-	tipc_bearers = NULL;
-	media_list = NULL;
 	media_count = 0;
 }
 
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index ca57348..000228e 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -114,7 +114,7 @@ struct bearer_name {
 
 struct link;
 
-extern struct bearer *tipc_bearers;
+extern struct bearer tipc_bearers[];
 
 void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a);
 struct sk_buff *tipc_media_get_names(void);
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 7906608..f25b1cd 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -116,7 +116,8 @@
 */
 
 DEFINE_RWLOCK(tipc_net_lock);
-struct network tipc_net = { NULL };
+struct _zone *tipc_zones[256] = { NULL, };
+struct network tipc_net = { tipc_zones };
 
 struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref)
 {
@@ -158,28 +159,12 @@ void tipc_net_send_external_routes(u32 dest)
 	}
 }
 
-static int net_init(void)
-{
-	memset(&tipc_net, 0, sizeof(tipc_net));
-	tipc_net.zones = kcalloc(tipc_max_zones + 1, sizeof(struct _zone *), GFP_ATOMIC);
-	if (!tipc_net.zones) {
-		return -ENOMEM;
-	}
-	return 0;
-}
-
 static void net_stop(void)
 {
 	u32 z_num;
 
-	if (!tipc_net.zones)
-		return;
-
-	for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
+	for (z_num = 1; z_num <= tipc_max_zones; z_num++)
 		tipc_zone_delete(tipc_net.zones[z_num]);
-	}
-	kfree(tipc_net.zones);
-	tipc_net.zones = NULL;
 }
 
 static void net_route_named_msg(struct sk_buff *buf)
@@ -282,9 +267,7 @@ int tipc_net_start(u32 addr)
 	tipc_named_reinit();
 	tipc_port_reinit();
 
-	if ((res = tipc_bearer_init()) ||
-	    (res = net_init()) ||
-	    (res = tipc_cltr_init()) ||
+	if ((res = tipc_cltr_init()) ||
 	    (res = tipc_bclink_init())) {
 		return res;
 	}

^ permalink raw reply related

* [patch] [iproute] ip exit, ip and tc line number
From: Michele Petrazzo - Unipex @ 2010-03-02 18:28 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: Type: text/plain, Size: 290 bytes --]

Hi,
I create a small patch that solve an annoying problem that I found on 
"ip -batch" usage, so the command exits without end the parsing of the 
batch file also if I specify the -force switch.
Also add the shown of the right line number where batch file fail for 
both ip and tc

Michele

[-- Attachment #2: iproute.diff --]
[-- Type: text/x-diff, Size: 1476 bytes --]

commit 805fac22865d50b561643e58f5c2c001439a6a7d
Author: Michele Petrazzo <michele.petrazzo@unipex.it>
Date:   Tue Mar 2 19:12:50 2010 +0100

    Resolving "ip" exit on batch usage and add to ip and tc commands
    the right line number on the output message then use with batch
    switch
    
    Signed-off-by: Michele Petrazzo <michele.petrazzo@unipex.it>

diff --git a/ip/ip.c b/ip/ip.c
index ace8cc6..b8c4914 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -125,6 +125,9 @@ static int batch(const char *name)
 			if (!force)
 				break;
 		}
+        else {
+            lineno++;
+        }
 	}
 	if (line)
 		free(line);
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index e9256d9..8ec6cfd 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -1014,7 +1014,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
 	}
 	if (l && matches(d, l) != 0) {
 		fprintf(stderr, "\"dev\" (%s) must match \"label\" (%s).\n", d, l);
-		exit(1);
+		return -1;
 	}
 
 	if (peer_len == 0 && local_len) {
@@ -1079,7 +1079,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
 	}
 
 	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
-		exit(2);
+		return -2;
 
 	return 0;
 }
diff --git a/tc/tc.c b/tc/tc.c
index 8e362d2..ce78621 100644
--- a/tc/tc.c
+++ b/tc/tc.c
@@ -250,6 +250,11 @@ static int batch(const char *name)
 			if (!force)
 				break;
 		}
+        else {
+            cmdlineno++;
+        }
+           
+
 	}
 	if (line)
 		free(line);

^ permalink raw reply related

* RE: [PATCH 0/8]: Bug fixes and new FW patch series
From: Vladislav Zolotarov @ 2010-03-02 19:14 UTC (permalink / raw)
  To: Vladislav Zolotarov, davem@davemloft.net; +Cc: netdev@vger.kernel.org
In-Reply-To: <1266408196.25691.841.camel@lb-tlvb-vladz>

Dave, it seems that u have forgotten to apply the 7-th patch from that series (the one that removes the old bnx2x firmware ver. 5.2.7).

The old .ihex files are still present in the master branch.

Could u, pls., check that u have applied the mentioned patch.

Thanks,
vlad

> -----Original Message-----
> From: netdev-owner@vger.kernel.org 
> [mailto:netdev-owner@vger.kernel.org] On Behalf Of Vladislav Zolotarov
> Sent: Wednesday, February 17, 2010 2:03 PM
> To: davem@davemloft.net
> Cc: netdev@vger.kernel.org
> Subject: [PATCH 0/8]: Bug fixes and new FW patch series
> 
> Dave, hi.
> Pls., apply the following series of patches.
> It includes a few bugs fixes and a few FW.
> 
> The patches may also be found at
> http://linux.broadcom.com/eilong/1.52.1-6
> 
> thanks,
> vlad
> 
> 
> --
> 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
> 
> 

^ permalink raw reply

* Re: [PATCH 0/8]: Bug fixes and new FW patch series
From: David Miller @ 2010-03-02 19:17 UTC (permalink / raw)
  To: vladz; +Cc: netdev
In-Reply-To: <8628FE4E7912BF47A96AE7DD7BAC0AADCB46A2B4A6@SJEXCHCCR02.corp.ad.broadcom.com>

From: "Vladislav Zolotarov" <vladz@broadcom.com>
Date: Tue, 2 Mar 2010 11:14:09 -0800

> Dave, it seems that u have forgotten to apply the 7-th patch from that series (the one that removes the old bnx2x firmware ver. 5.2.7).
> 
> The old .ihex files are still present in the master branch.
> 
> Could u, pls., check that u have applied the mentioned patch.

If it's not applied, I don't have it any more and you need
to resend it to me.

^ permalink raw reply

* RE: [PATCH 0/8]: Bug fixes and new FW patch series
From: Vladislav Zolotarov @ 2010-03-02 19:40 UTC (permalink / raw)
  To: David Miller; +Cc: netdev@vger.kernel.org
In-Reply-To: <20100302.111719.211474245.davem@davemloft.net>

The patches are still availiable at:
http://linux.broadcom.com/eilong/1.52.1-6 

It seems like the patch 7 hasn't been applied (remove old .ihex files)

Could u apply it, plz.

vlad

> -----Original Message-----
> From: David Miller [mailto:davem@davemloft.net] 
> Sent: Tuesday, March 02, 2010 9:17 PM
> To: Vladislav Zolotarov
> Cc: netdev@vger.kernel.org
> Subject: Re: [PATCH 0/8]: Bug fixes and new FW patch series
> 
> From: "Vladislav Zolotarov" <vladz@broadcom.com>
> Date: Tue, 2 Mar 2010 11:14:09 -0800
> 
> > Dave, it seems that u have forgotten to apply the 7-th 
> patch from that series (the one that removes the old bnx2x 
> firmware ver. 5.2.7).
> > 
> > The old .ihex files are still present in the master branch.
> > 
> > Could u, pls., check that u have applied the mentioned patch.
> 
> If it's not applied, I don't have it any more and you need
> to resend it to me.
> 
> 

^ permalink raw reply

* RE: [PATCH 0/8]: Bug fixes and new FW patch series
From: Vladislav Zolotarov @ 2010-03-02 19:42 UTC (permalink / raw)
  To: David Miller; +Cc: netdev@vger.kernel.org
In-Reply-To: <20100217.134451.10225453.davem@davemloft.net>

I'll surely do. Sorry for the inconvenience. 

vlad

> -----Original Message-----
> From: David Miller [mailto:davem@davemloft.net] 
> Sent: Wednesday, February 17, 2010 11:45 PM
> To: Vladislav Zolotarov
> Cc: netdev@vger.kernel.org
> Subject: Re: [PATCH 0/8]: Bug fixes and new FW patch series
> 
> From: "Vladislav Zolotarov" <vladz@broadcom.com>
> Date: Wed, 17 Feb 2010 14:03:16 +0200
> 
> > Dave, hi.
> > Pls., apply the following series of patches.
> > It includes a few bugs fixes and a few FW.
> > 
> > The patches may also be found at
> > http://linux.broadcom.com/eilong/1.52.1-6
> 
> All applied, but please coordinate better with changes coming in via
> your colleages.
> 
> Patch #6 would not apply cleanly because the firmware/Makefile is
> different due to the bnx2 driver firmware updates made yesterday.
> 
> I fixed it up by hand, but in the future apply patches that apply
> cleanly to the current tree.
> 
> Thanks.
> 
> 

^ permalink raw reply

* Re: [PATCH 0/8]: Bug fixes and new FW patch series
From: David Miller @ 2010-03-02 19:46 UTC (permalink / raw)
  To: vladz; +Cc: netdev
In-Reply-To: <8628FE4E7912BF47A96AE7DD7BAC0AADCB46A2B4AF@SJEXCHCCR02.corp.ad.broadcom.com>

From: "Vladislav Zolotarov" <vladz@broadcom.com>
Date: Tue, 2 Mar 2010 11:40:20 -0800

> The patches are still availiable at:
> http://linux.broadcom.com/eilong/1.52.1-6 
> 
> It seems like the patch 7 hasn't been applied (remove old .ihex files)
> 
> Could u apply it, plz.

This is so frustrating.

What part of "you need to resend it to me" do you not understand?

I'm not going to your web sites to grab your patches, I use patchwork
and my email inbox as my work queue.

^ permalink raw reply

* Re: e1000e: reset of tx_queue_len
From: Franco Fichtner @ 2010-03-02 19:52 UTC (permalink / raw)
  To: Brandeburg, Jesse; +Cc: Netdev, Allan, Bruce W
In-Reply-To: <alpine.WNT.2.00.1003021020160.2888@jbrandeb-desk1.amr.corp.intel.com>

Brandeburg, Jesse wrote:
> On Tue, 2 Mar 2010, Franco Fichtner wrote:
>   
>> while working on a new server, I noticed that tx_queue_len is reset
>> to the default of 1000 while ADDRCONF(NETDEV_CHANGE).
>> This happens with 2.6.30.8, but I could not see any obvious
>> differences to the current state of e1000e, while trying to find the
>> problem in the code.
>>     
>
> The driver tries to set the queuelen back to 1000 if the link changes 
> speed, because the driver tries to shorten the txqueuelen to 100 to reduce 
> latency when the link changes to 100/10 Mb/s
>   

Thanks, that explains it. Since we don't connect ports at startup, the 
plugging causes
a speed "change".

>> The interface has been configured including a customized qlen
>> via /etc/network/interfaces. The ports are not connected at startup
>> so obviously the Kernel reports
>>
>> ADDRCONF(NETDEV_UP): eth2: link is not ready
>>     
>
> do your scripts try to configure the queuelen when link is not up?  Why 
> are the ports not connected at startup?
>   

I have a modified up command that sets appropriate values of mtu and 
qlen via ip. The device is
brought up at startup automatically with the correct values. At least 
that's what ifconfig shows
even though the port is not yet connected.

There has been a lot of testing back and forth with single hosts and 
much larger quantities of traffic.
This got really messy when testing single host first (connected via 100 
Mb/s, so qlen to 100) and then
switching to 1000 Mb/s. qlen would still be 100, causing lots of packet 
drops. This took a few
days to track down, unfortunately.

> Hope this helps

Greatly appreciated, thanks again. :)


Franco

^ permalink raw reply

* RE: [PATCH 0/8]: Bug fixes and new FW patch series
From: Vladislav Zolotarov @ 2010-03-02 20:05 UTC (permalink / raw)
  To: David Miller; +Cc: netdev@vger.kernel.org
In-Reply-To: <20100302.114623.119214667.davem@davemloft.net>

I thought u were taking "FW add/remove" patches from the ftp/http sites and not from your mailbox.
The patch is on its way to your mailbox... ;) 

Thanks,
vlad

> -----Original Message-----
> From: David Miller [mailto:davem@davemloft.net] 
> Sent: Tuesday, March 02, 2010 9:46 PM
> To: Vladislav Zolotarov
> Cc: netdev@vger.kernel.org
> Subject: Re: [PATCH 0/8]: Bug fixes and new FW patch series
> 
> From: "Vladislav Zolotarov" <vladz@broadcom.com>
> Date: Tue, 2 Mar 2010 11:40:20 -0800
> 
> > The patches are still availiable at:
> > http://linux.broadcom.com/eilong/1.52.1-6 
> > 
> > It seems like the patch 7 hasn't been applied (remove old 
> .ihex files)
> > 
> > Could u apply it, plz.
> 
> This is so frustrating.
> 
> What part of "you need to resend it to me" do you not understand?
> 
> I'm not going to your web sites to grab your patches, I use patchwork
> and my email inbox as my work queue.
> 
> 

^ permalink raw reply

* [RFC v2 00/10] snet: Security for NETwork syscalls
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes

Hello lsm and netdev people,
This set of patches is the version 2 of snet, which I would like to submit as a
RFC.

snet is a linux security module. It provides a mecanism defering syscall
security hooks and decision (verdict) to userspace. 

snet has some subsystems :
    - snet_core     : init and exit the system
    - snet_hooks    : LSM hooks
    - snet_netlink  : kernel-user communication (genetlink)
    - snet_event    : manages the list of protected syscalls
    - snet_verdict  : provides a waitqueue for syscalls and manage verdicts
    - snet_ticket   : provides a granted-access ticket mecanism

I believe that snet will help to get over the classical configuration
complexity of others security modules, by providing interactivity to users.
I also think that monolithic strategy is broken with snet, as we can provide
security for others syscall's categories:
 - sfs  : security for filesystem,
 - stask: security for task,
 - smem : security for memory
 ..

In this way, and by putting abstraction on how this subsystems can talk to each
others, we may use the security combinaison we want: choose to run sfs,
stask, but not snet nor smem. Better, developpers may investigated how to build
another security subsystem for tasks, and use others existing (smem, snet..)
which they don't want to modify

I think that interactivity is very usefull for users, as they may be notify when
something is wrong and take decision, and from userspace, the decision may be
defered to another box. In this way, snet also have a advantage for mobile
devices as the policy decision will be push to a distant server, mobile device
will then wait for verdicts and as policy strategies are centralized.

Finally, and a important point: snet integration respects the LSM framework idea
of using LSM hooks.

New feature from the previous version:
 * Building a ticket mecanism for each task_struct using pointer void *security
   Use the pointer (void*) security related to task_struct to provides
   granted-acces tickets: if two identical requests are coming, ask the user
   for the first one, store the result in a ticket and for the second request,
   just look in the tickets owned by the task-struct
 * send data buffer of sendmsg to userspace
   this may provide a way to look inside the data (as a anti-virus do)

roadmap:
 * find a way to send data buffer of sendmsg to userspace (using netfilter)
 * adding other security systems
   we can think about adding fork(), exec(), open(), close()..

I'm Ccing netfilter-devel, as snet may be seen as a way to do filtering.

Samir Bellabes (10):
  lsm: add security_socket_closed()
  Revert "lsm: Remove the socket_post_accept() hook"
  snet: introduce security/snet, Makefile and Kconfig changes
  snet: introduce snet_core
  snet: introduce snet_event
  snet: introduce snet_hooks
  snet: introduce snet_netlink
  snet: introduce snet_verdict
  snet: introduce snet_ticket
  snet: introduce snet_utils

 include/linux/security.h            |   23 ++
 include/linux/snet.h                |  120 ++++++
 net/socket.c                        |    3 +
 security/Kconfig                    |    6 +
 security/Makefile                   |    2 +
 security/capability.c               |   10 +
 security/security.c                 |   10 +
 security/snet/Kconfig               |   11 +
 security/snet/Makefile              |   14 +
 security/snet/snet_core.c           |   76 ++++
 security/snet/snet_event.c          |  189 ++++++++++
 security/snet/snet_event.h          |   21 +
 security/snet/snet_hooks.c          |  710 +++++++++++++++++++++++++++++++++++
 security/snet/snet_hooks.h          |   10 +
 security/snet/snet_netlink.c        |  431 +++++++++++++++++++++
 security/snet/snet_netlink.h        |   17 +
 security/snet/snet_netlink_helper.c |  230 +++++++++++
 security/snet/snet_netlink_helper.h |    7 +
 security/snet/snet_ticket.c         |  171 +++++++++
 security/snet/snet_ticket.h         |   37 ++
 security/snet/snet_ticket_helper.c  |  127 +++++++
 security/snet/snet_ticket_helper.h  |    8 +
 security/snet/snet_utils.c          |   38 ++
 security/snet/snet_utils.h          |   10 +
 security/snet/snet_verdict.c        |  184 +++++++++
 security/snet/snet_verdict.h        |   23 ++
 26 files changed, 2488 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/snet.h
 create mode 100644 security/snet/Kconfig
 create mode 100644 security/snet/Makefile
 create mode 100644 security/snet/snet_core.c
 create mode 100644 security/snet/snet_event.c
 create mode 100644 security/snet/snet_event.h
 create mode 100644 security/snet/snet_hooks.c
 create mode 100644 security/snet/snet_hooks.h
 create mode 100644 security/snet/snet_netlink.c
 create mode 100644 security/snet/snet_netlink.h
 create mode 100644 security/snet/snet_netlink_helper.c
 create mode 100644 security/snet/snet_netlink_helper.h
 create mode 100644 security/snet/snet_ticket.c
 create mode 100644 security/snet/snet_ticket.h
 create mode 100644 security/snet/snet_ticket_helper.c
 create mode 100644 security/snet/snet_ticket_helper.h
 create mode 100644 security/snet/snet_utils.c
 create mode 100644 security/snet/snet_utils.h
 create mode 100644 security/snet/snet_verdict.c
 create mode 100644 security/snet/snet_verdict.h


^ permalink raw reply

* [RFC v2 01/10] lsm: add security_socket_closed()
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

Allow a security module to update security informations when a socket is closed.

Signed-off-by: Samir Bellabes <sam@synack.fr>
---
 include/linux/security.h |   10 ++++++++++
 net/socket.c             |    1 +
 security/capability.c    |    5 +++++
 security/security.c      |    5 +++++
 4 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 2c627d3..74e564b 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -981,6 +981,9 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	@sock contains the socket structure.
  *	@how contains the flag indicating how future sends and receives are handled.
  *	Return 0 if permission is granted.
+ * @socket_close:
+ *	Allow a module to update security informations when a socket is closed
+ *	@sock is closed.
  * @socket_sock_rcv_skb:
  *	Check permissions on incoming network packets.  This hook is distinct
  *	from Netfilter's IP input hooks since it is the first time that the
@@ -1680,6 +1683,7 @@ struct security_operations {
 	int (*socket_getsockopt) (struct socket *sock, int level, int optname);
 	int (*socket_setsockopt) (struct socket *sock, int level, int optname);
 	int (*socket_shutdown) (struct socket *sock, int how);
+	void (*socket_close) (struct socket *sock);
 	int (*socket_sock_rcv_skb) (struct sock *sk, struct sk_buff *skb);
 	int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
 	int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid);
@@ -2700,6 +2704,7 @@ int security_socket_getpeername(struct socket *sock);
 int security_socket_getsockopt(struct socket *sock, int level, int optname);
 int security_socket_setsockopt(struct socket *sock, int level, int optname);
 int security_socket_shutdown(struct socket *sock, int how);
+void security_socket_close(struct socket *sock);
 int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb);
 int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
 				      int __user *optlen, unsigned len);
@@ -2812,6 +2817,11 @@ static inline int security_socket_shutdown(struct socket *sock, int how)
 {
 	return 0;
 }
+
+static inline void security_socket_close(struct socket *sock)
+{
+}
+
 static inline int security_sock_rcv_skb(struct sock *sk,
 					struct sk_buff *skb)
 {
diff --git a/net/socket.c b/net/socket.c
index 769c386..b4eb361 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1055,6 +1055,7 @@ static int sock_close(struct inode *inode, struct file *filp)
 		printk(KERN_DEBUG "sock_close: NULL inode\n");
 		return 0;
 	}
+	security_socket_close(SOCKET_I(inode));
 	sock_release(SOCKET_I(inode));
 	return 0;
 }
diff --git a/security/capability.c b/security/capability.c
index 5c700e1..a9810dc 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -677,6 +677,10 @@ static int cap_socket_shutdown(struct socket *sock, int how)
 	return 0;
 }
 
+static void cap_socket_close(struct socket *sock)
+{
+}
+
 static int cap_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
 	return 0;
@@ -1084,6 +1088,7 @@ void security_fixup_ops(struct security_operations *ops)
 	set_to_cap_if_null(ops, socket_setsockopt);
 	set_to_cap_if_null(ops, socket_getsockopt);
 	set_to_cap_if_null(ops, socket_shutdown);
+	set_to_cap_if_null(ops, socket_close);
 	set_to_cap_if_null(ops, socket_sock_rcv_skb);
 	set_to_cap_if_null(ops, socket_getpeersec_stream);
 	set_to_cap_if_null(ops, socket_getpeersec_dgram);
diff --git a/security/security.c b/security/security.c
index 122b748..288c3a8 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1118,6 +1118,11 @@ int security_socket_shutdown(struct socket *sock, int how)
 	return security_ops->socket_shutdown(sock, how);
 }
 
+void security_socket_close(struct socket *sock)
+{
+	return security_ops->socket_close(sock);
+}
+
 int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
 	return security_ops->socket_sock_rcv_skb(sk, skb);
-- 
1.6.3.3


^ permalink raw reply related

* [RFC v2 02/10] Revert "lsm: Remove the socket_post_accept() hook"
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

This reverts commit 8651d5c0b1f874c5b8307ae2b858bc40f9f02482.

snet needs to reintroduce this hook, as it was designed to be: a hook for
updating security informations on objects.

Signed-off-by: Samir Bellabes <sam@synack.fr>
Acked-by: Serge Hallyn <serue@us.ibm.com>
---
 include/linux/security.h |   13 +++++++++++++
 net/socket.c             |    2 ++
 security/capability.c    |    5 +++++
 security/security.c      |    5 +++++
 4 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 74e564b..d8ad624 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -938,6 +938,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	@sock contains the listening socket structure.
  *	@newsock contains the newly created server socket for connection.
  *	Return 0 if permission is granted.
+ * @socket_post_accept:
+ *	This hook allows a security module to copy security
+ *	information into the newly created socket's inode.
+ *	@sock contains the listening socket structure.
+ *	@newsock contains the newly created server socket for connection.
  * @socket_sendmsg:
  *	Check permission before transmitting a message to another socket.
  *	@sock contains the socket structure.
@@ -1674,6 +1679,8 @@ struct security_operations {
 			       struct sockaddr *address, int addrlen);
 	int (*socket_listen) (struct socket *sock, int backlog);
 	int (*socket_accept) (struct socket *sock, struct socket *newsock);
+	void (*socket_post_accept) (struct socket *sock,
+				    struct socket *newsock);
 	int (*socket_sendmsg) (struct socket *sock,
 			       struct msghdr *msg, int size);
 	int (*socket_recvmsg) (struct socket *sock,
@@ -2696,6 +2703,7 @@ int security_socket_bind(struct socket *sock, struct sockaddr *address, int addr
 int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen);
 int security_socket_listen(struct socket *sock, int backlog);
 int security_socket_accept(struct socket *sock, struct socket *newsock);
+void security_socket_post_accept(struct socket *sock, struct socket *newsock);
 int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size);
 int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
 			    int size, int flags);
@@ -2778,6 +2786,11 @@ static inline int security_socket_accept(struct socket *sock,
 	return 0;
 }
 
+static inline void security_socket_post_accept(struct socket *sock,
+					       struct socket *newsock)
+{
+}
+
 static inline int security_socket_sendmsg(struct socket *sock,
 					  struct msghdr *msg, int size)
 {
diff --git a/net/socket.c b/net/socket.c
index b4eb361..2e66a5a 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1538,6 +1538,8 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
 	fd_install(newfd, newfile);
 	err = newfd;
 
+	security_socket_post_accept(sock, newsock);
+
 out_put:
 	fput_light(sock->file, fput_needed);
 out:
diff --git a/security/capability.c b/security/capability.c
index a9810dc..61eae40 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -641,6 +641,10 @@ static int cap_socket_accept(struct socket *sock, struct socket *newsock)
 	return 0;
 }
 
+static void cap_socket_post_accept(struct socket *sock, struct socket *newsock)
+{
+}
+
 static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
 {
 	return 0;
@@ -1081,6 +1085,7 @@ void security_fixup_ops(struct security_operations *ops)
 	set_to_cap_if_null(ops, socket_connect);
 	set_to_cap_if_null(ops, socket_listen);
 	set_to_cap_if_null(ops, socket_accept);
+	set_to_cap_if_null(ops, socket_post_accept);
 	set_to_cap_if_null(ops, socket_sendmsg);
 	set_to_cap_if_null(ops, socket_recvmsg);
 	set_to_cap_if_null(ops, socket_getsockname);
diff --git a/security/security.c b/security/security.c
index 288c3a8..673979f 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1082,6 +1082,11 @@ int security_socket_accept(struct socket *sock, struct socket *newsock)
 	return security_ops->socket_accept(sock, newsock);
 }
 
+void security_socket_post_accept(struct socket *sock, struct socket *newsock)
+{
+	security_ops->socket_post_accept(sock, newsock);
+}
+
 int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
 {
 	return security_ops->socket_sendmsg(sock, msg, size);
-- 
1.6.3.3


^ permalink raw reply related

* [RFC v2 03/10] snet: introduce security/snet, Makefile and Kconfig changes
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

this patch creates folder security/snet and adds changes for Kconfig and Makefile

Signed-off-by: Samir Bellabes <sam@synack.fr>
---
 security/Kconfig       |    6 ++++++
 security/Makefile      |    2 ++
 security/snet/Kconfig  |   11 +++++++++++
 security/snet/Makefile |   14 ++++++++++++++
 4 files changed, 33 insertions(+), 0 deletions(-)
 create mode 100644 security/snet/Kconfig
 create mode 100644 security/snet/Makefile

diff --git a/security/Kconfig b/security/Kconfig
index 226b955..eb37e9a 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -140,6 +140,7 @@ config LSM_MMAP_MIN_ADDR
 source security/selinux/Kconfig
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
+source security/snet/Kconfig
 
 source security/integrity/ima/Kconfig
 
@@ -148,6 +149,7 @@ choice
 	default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX
 	default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
 	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
+	default DEFAULT_SECURITY_SNET if SECURITY_SNET
 	default DEFAULT_SECURITY_DAC
 
 	help
@@ -163,6 +165,9 @@ choice
 	config DEFAULT_SECURITY_TOMOYO
 		bool "TOMOYO" if SECURITY_TOMOYO=y
 
+	config DEFAULT_SECURITY_SNET
+		bool "snet" if SECURITY_SNET=y
+
 	config DEFAULT_SECURITY_DAC
 		bool "Unix Discretionary Access Controls"
 
@@ -173,6 +178,7 @@ config DEFAULT_SECURITY
 	default "selinux" if DEFAULT_SECURITY_SELINUX
 	default "smack" if DEFAULT_SECURITY_SMACK
 	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
+	default "snet" if DEFAULT_SECURITY_SNET
 	default "" if DEFAULT_SECURITY_DAC
 
 endmenu
diff --git a/security/Makefile b/security/Makefile
index da20a19..9374523 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_KEYS)			+= keys/
 subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux
 subdir-$(CONFIG_SECURITY_SMACK)		+= smack
 subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
+subdir-$(CONFIG_SECURITY_SNET)		+= snet
 
 # always enable default capabilities
 obj-y					+= commoncap.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)		+= smack/built-in.o
 obj-$(CONFIG_AUDIT)			+= lsm_audit.o
 obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/built-in.o
+obj-$(CONFIG_SECURITY_SNET)		+= snet/built-in.o
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
 # Object integrity file lists
diff --git a/security/snet/Kconfig b/security/snet/Kconfig
new file mode 100644
index 0000000..6dabd7d
--- /dev/null
+++ b/security/snet/Kconfig
@@ -0,0 +1,11 @@
+#
+# snet
+#
+
+config SECURITY_SNET
+	bool "snet - Security for NETwork syscalls"
+	depends on SECURITY_NETWORK
+	default n
+	---help---
+	If this option is enabled, the kernel will include support for reporting
+	networking's syscalls to userspace and wait for a verdict
diff --git a/security/snet/Makefile b/security/snet/Makefile
new file mode 100644
index 0000000..e8f52f1
--- /dev/null
+++ b/security/snet/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for building the Security Network Events module.
+#
+obj-$(CONFIG_SECURITY_SNET) :=  snet.o
+
+snet-y := snet_event.o \
+	  snet_netlink_helper.o \
+	  snet_netlink.o \
+	  snet_verdict.o \
+	  snet_ticket_helper.o \
+	  snet_ticket.o \
+	  snet_hooks.o \
+	  snet_core.o \
+	  snet_utils.o
-- 
1.6.3.3

^ permalink raw reply related

* [RFC v2 04/10] snet: introduce snet_core
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

this patch introduce snet_core.c, which provides functions to start and stop
snet's subsystems, and include/linux/snet.h, which provides interface with
userspace

subsytems are:
    - snet_hooks    : LSM hooks
    - snet_netlink  : kernel-user communication (genetlink)
    - snet_event    : manages the list of protected syscalls
    - snet_verdict  : provides a waitqueue for syscalls and manage verdicts
		      from userspace
    - snet_ticket   : provides a granted-access ticket mecanism

Signed-off-by: Samir Bellabes <sam@synack.fr>
---
 include/linux/snet.h      |  120 +++++++++++++++++++++++++++++++++++++++++++++
 security/snet/snet_core.c |   76 ++++++++++++++++++++++++++++
 2 files changed, 196 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/snet.h
 create mode 100644 security/snet/snet_core.c

diff --git a/include/linux/snet.h b/include/linux/snet.h
new file mode 100644
index 0000000..739601d
--- /dev/null
+++ b/include/linux/snet.h
@@ -0,0 +1,120 @@
+#ifndef _LINUX_SNET_H
+#define _LINUX_SNET_H
+
+#include <linux/in6.h>
+
+#define SNET_VERSION	0x1
+#define SNET_NAME	"snet"
+
+enum snet_syscall {
+	SNET_SOCKET_CREATE = 0,
+	SNET_SOCKET_BIND,
+	SNET_SOCKET_CONNECT,
+	SNET_SOCKET_LISTEN,
+	SNET_SOCKET_ACCEPT,
+	SNET_SOCKET_POST_ACCEPT,
+	SNET_SOCKET_SENDMSG,
+	SNET_SOCKET_RECVMSG,
+	SNET_SOCKET_SOCK_RCV_SKB,
+	SNET_SOCKET_CLOSE,
+	SNET_SOCKET_INVALID,
+};
+
+#define SNET_NR_SOCKET_TYPES SNET_SOCKET_INVALID
+
+struct snet_event {
+	enum snet_syscall syscall;
+	u8 protocol;
+};
+
+enum snet_verdict {
+	SNET_VERDICT_GRANT = 0,	/* grant the syscall */
+	SNET_VERDICT_DENY,	/* deny the syscall */
+	SNET_VERDICT_PENDING,	/* waiting for a decision */
+	SNET_VERDICT_NONE,	/* no decision can be set */
+	SNET_VERDICT_INVALID,
+};
+
+#define SNET_NR_VERDICT_TYPES SNET_VERDICT_INVALID
+
+enum snet_ticket_mode {
+	SNET_TICKET_OFF = 0,
+	SNET_TICKET_FIX,
+	SNET_TICKET_EXTEND,
+};
+
+/* genetlink commands */
+enum {
+	SNET_C_UNSPEC,
+	SNET_C_VERSION,
+	SNET_C_REGISTER,
+	SNET_C_UNREGISTER,
+	SNET_C_INSERT,
+	SNET_C_REMOVE,
+	SNET_C_FLUSH,
+	SNET_C_LIST,
+	SNET_C_VERDICT,
+	SNET_C_CONFIG,
+	__SNET_C_MAX,
+};
+
+#define SNET_C_MAX (__SNET_C_MAX - 1)
+
+/* genetlink attributes */
+enum {
+	SNET_A_UNSPEC,
+	SNET_A_VERSION,		/* (NLA_U32) the snet protocol version	*/
+	SNET_A_VERDICT_ID,
+	SNET_A_FAMILY,
+	SNET_A_SYSCALL,		/* (NLA_U8)  a syscall identifier	*/
+	SNET_A_PROTOCOL,	/* (NLA_U8)  a protocol identifier	*/
+	SNET_A_UID,
+	SNET_A_PID,
+	SNET_A_TYPE,
+	SNET_A_IPV4SADDR,
+	SNET_A_IPV6SADDR,
+	SNET_A_IPV4DADDR,
+	SNET_A_IPV6DADDR,
+	SNET_A_SPORT,
+	SNET_A_DPORT,
+	SNET_A_BUFFER,
+	SNET_A_BUFFER_LEN,
+	SNET_A_VERDICT,
+	SNET_A_VERDICT_DELAY,
+	SNET_A_TICKET_DELAY,
+	SNET_A_TICKET_MODE,
+	__SNET_A_MAX,
+};
+
+#define SNET_A_MAX (__SNET_A_MAX - 1)
+
+#define SNET_GENL_NAME		"SNET"
+#define SNET_GENL_VERSION	SNET_VERSION
+
+struct snet_sock_half {
+	struct {
+		union {
+			__be32 ip;
+			struct in6_addr ip6;
+		};
+	} u3;
+	struct {
+		__be16 port;
+	} u;
+};
+
+struct snet_info {
+	u32 verdict_id;
+
+	enum snet_syscall syscall;
+	u8 protocol;
+	u8 family;
+
+	int type;
+	struct snet_sock_half src;
+	struct snet_sock_half dst;
+	void *buffer;
+	int len;
+};
+
+#endif /* _LINUX_SNET_H */
diff --git a/security/snet/snet_core.c b/security/snet/snet_core.c
new file mode 100644
index 0000000..9f2eb2e
--- /dev/null
+++ b/security/snet/snet_core.c
@@ -0,0 +1,76 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <net/genetlink.h>
+#include <linux/snet.h>
+#include "snet_hooks.h"
+#include "snet_event.h"
+#include "snet_verdict.h"
+#include "snet_ticket.h"
+#include "snet_utils.h"
+
+unsigned int snet_evh_size = 16;
+module_param(snet_evh_size, uint, 0400);
+MODULE_PARM_DESC(snet_evh_size, "Set the size of the event hash table");
+
+unsigned int snet_vdh_size = 16;
+module_param(snet_vdh_size, uint, 0400);
+MODULE_PARM_DESC(snet_vdh_size, "Set the size of the verdict hash table");
+
+unsigned int snet_verdict_delay = 5;
+module_param(snet_verdict_delay, uint, 0600);
+MODULE_PARM_DESC(snet_verdict_delay, "Set the timeout for verdicts in secs");
+
+unsigned int snet_verdict_policy = SNET_VERDICT_GRANT;	/* permissive by default */
+module_param(snet_verdict_policy, uint, 0400);
+MODULE_PARM_DESC(snet_verdict_policy, "Set the default verdict");
+
+unsigned int snet_ticket_delay = 15;
+module_param(snet_ticket_delay, uint, 0600);
+MODULE_PARM_DESC(snet_ticket_delay, "Set the timeout for tickets in secs");
+
+unsigned int snet_ticket_mode = SNET_TICKET_FIX;
+module_param(snet_ticket_mode, uint, 0600);
+MODULE_PARM_DESC(snet_ticket_mode, "Set the mode for tickets");
+
+static __init int snet_init(void)
+{
+	int ret;
+
+	pr_debug("initializing: event_hash_size=%u "
+		 "verdict_hash_size=%u verdict_delay=%usecs "
+		 "default_policy=%s\n",
+		 snet_evh_size, snet_vdh_size, snet_verdict_delay,
+		 snet_verdict_name(snet_verdict_policy));
+
+	ret = snet_event_init();
+	if (ret < 0)
+		goto event_failed;
+
+	ret = snet_verdict_init();
+	if (ret < 0)
+		goto verdict_failed;
+
+	ret = snet_ticket_init();
+	if (ret < 0)
+		goto ticket_failed;
+
+	/* snet_hooks_init() returns 0 or execute panic() */
+	snet_hooks_init();
+
+	pr_debug("started\n");
+	return 0;
+
+ticket_failed:
+	snet_verdict_exit();
+verdict_failed:
+	snet_event_exit();
+event_failed:
+	pr_debug("stopped\n");
+	return ret;
+}
+
+security_initcall(snet_init);
+
+MODULE_DESCRIPTION("snet - Security for NETwork syscalls");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Samir Bellabes <sam@synack.fr>");
-- 
1.6.3.3

^ permalink raw reply related

* [RFC v2 06/10] snet: introduce snet_hooks
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

This patch adds the snet LSM's subsystem

snet_hooks provides the security hook's functions and the security_operations
structure. Currently hook functions are only related to network stack.

For each hook function, there is a generic mecanism:
 0. check if the event [syscall, protocol] is registered
 1. prepare informations for userspace
 2. send informations to userspace (snet_netlink)
 3. wait for verdict from userspace (snet_verdict)
 4. apply verdict for the syscall

steps 3 and 4 are only valid for LSM hooks which are returning a value (a way to
'filter' the syscall). For hooks returning 'void', steps 3 and 4 don't exist,
but snet sends security informations to userspace (step 2) to update the global
security policy.

Signed-off-by: Samir Bellabes <sam@synack.fr>
---
 security/snet/snet_hooks.c |  710 ++++++++++++++++++++++++++++++++++++++++++++
 security/snet/snet_hooks.h |   10 +
 2 files changed, 720 insertions(+), 0 deletions(-)
 create mode 100644 security/snet/snet_hooks.c
 create mode 100644 security/snet/snet_hooks.h

diff --git a/security/snet/snet_hooks.c b/security/snet/snet_hooks.c
new file mode 100644
index 0000000..689babe
--- /dev/null
+++ b/security/snet/snet_hooks.c
@@ -0,0 +1,710 @@
+/*
+ * snet_hook.c
+ *
+ * here are interesting informations which can be picked up from hooks.
+ *
+ *
+ * SOCKET_CREATE:
+ *	family, type, protocol
+ * SOCKET_BIND:
+ *	family, protocol, saddr, sport
+ * SOCKET_CONNECT:
+ *	family, protocol, saddr, sport, daddr, dport
+ * SOCKET_LISTEN:
+ *	family, protocol, saddr, sport
+ * SOCKET_ACCEPT:
+ *	family, protocol, saddr, sport
+ *
+ * SOCKET_SENDMSG:
+ * SOCKET_RECVMSG:
+ * SOCKET_SOCK_RCV_SKB:
+ *
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/security.h>
+#include <linux/net.h>
+#include <net/sock.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <net/inet_sock.h>
+#include <linux/ipv6.h>
+#include <linux/snet.h>
+#include "snet_hooks.h"
+#include "snet_verdict.h"
+#include "snet_netlink.h"
+#include "snet_event.h"
+#include "snet_ticket.h"
+
+static inline void  snet_pr_tuple(struct snet_info *info)
+{
+	switch (info->family) {
+	case AF_INET:
+		pr_debug("%pI4:%u->%pI4:%u\n",
+			 &info->src.u3.ip, info->src.u.port,
+			 &info->dst.u3.ip, info->dst.u.port);
+		break;
+	case AF_INET6:
+		pr_debug("%pI6:%u->%pI6:%u\n",
+			 &info->src.u3.ip6, info->src.u.port,
+			 &info->dst.u3.ip6, info->dst.u.port);
+		break;
+	default:
+		break;
+	}
+	return;
+}
+
+static inline int snet_check_listeners(enum snet_verdict *verdict)
+{
+	if (snet_nl_pid == 0 || snet_nl_pid == current->pid ) {
+		if (verdict != NULL)
+			*verdict = SNET_VERDICT_GRANT;
+		return -1;
+	}
+	return 0;
+}
+
+static int snet_do_verdict(enum snet_verdict *verdict, struct snet_info *info)
+{
+	if (info->verdict_id == 0)
+		return -1;
+	/* sending networking informations to userspace */
+	if (snet_nl_send_event(info) == 0)
+		/* waiting for userspace reply or timeout */
+		*verdict = snet_verdict_wait(info->verdict_id);
+	/* removing verdict */
+	snet_verdict_remove(info->verdict_id);
+	return 0;
+}
+
+static void snet_do_send_event(struct snet_info *info)
+{
+	snet_nl_send_event(info);
+	return;
+}
+
+/*
+ * security operations helper functions
+ */
+
+/*
+ * security operations functions members
+ */
+
+static int snet_socket_create(int family, int type, int protocol, int kern)
+{
+	enum snet_verdict verdict = SNET_VERDICT_NONE;
+
+	/* if (kern) */
+	/*	;		/\* do something smart *\/ */
+
+	if (snet_check_listeners(&verdict) < 0)
+		goto out;
+
+	if (snet_event_is_registered(SNET_SOCKET_CREATE, protocol)) {
+		struct snet_info info;
+
+		/* inserting verdict PENDING */
+		info.verdict_id = snet_verdict_insert();
+
+		/* prepare networking informations for userspace */
+		info.syscall = SNET_SOCKET_CREATE;
+		info.protocol = protocol;
+		info.family = family;
+		info.type = type;
+
+		pr_debug("family=%u type=%u protocol=%u kern=%u\n",
+			 family, type, protocol, kern);
+
+		snet_do_verdict(&verdict, &info);
+
+	} else {
+		verdict = SNET_VERDICT_GRANT;
+	}
+
+	if (verdict == SNET_VERDICT_NONE)
+		verdict = snet_verdict_policy;
+
+out:
+	return verdict;
+}
+
+static int snet_socket_bind(struct socket *sock,
+			    struct sockaddr *address, int addrlen)
+{
+	enum snet_verdict verdict = SNET_VERDICT_NONE;
+	u8 protocol = 0;
+
+	if (snet_check_listeners(&verdict) < 0)
+		goto out;
+
+	protocol = sock->sk->sk_protocol;
+
+	if (snet_event_is_registered(SNET_SOCKET_BIND, protocol)) {
+		struct snet_info info;
+		struct inet_sock *inet = inet_sk(sock->sk);
+		struct sockaddr_in *a = (struct sockaddr_in *) address;
+		struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) address;
+
+		/* prepare networking informations for userspace */
+		info.syscall = SNET_SOCKET_BIND;
+		info.protocol = protocol;
+		info.family = sock->sk->sk_family;
+		info.dst.u.port = ntohs(inet->inet_dport);
+
+		switch (sock->sk->sk_family) {
+		case PF_INET:
+			info.src.u3.ip = a->sin_addr.s_addr;
+			info.dst.u3.ip = inet->inet_daddr;
+			info.src.u.port = ntohs(a->sin_port);
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		case PF_INET6:
+			memcpy(&info.src.u3.ip6, (void *)&a6->sin6_addr,
+			       sizeof(info.src.u3.ip6));
+			memcpy(&info.dst.u3.ip6, (void *)&inet->pinet6->daddr,
+			       sizeof(info.dst.u3.ip6));
+			info.src.u.port = ntohs(a6->sin6_port);
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#endif
+		default:
+			verdict = SNET_VERDICT_NONE;
+			goto skip_send_wait;
+			break;
+		}
+		snet_pr_tuple(&info);
+		snet_do_verdict(&verdict, &info);
+		/* create ticket */
+		snet_ticket_create(&info, verdict);
+	} else {
+		verdict = SNET_VERDICT_GRANT;
+	}
+
+skip_send_wait:
+	if (verdict == SNET_VERDICT_NONE)
+		verdict = snet_verdict_policy;
+out:
+	return verdict;
+}
+
+static int snet_socket_connect(struct socket *sock,
+			       struct sockaddr *address, int addrlen)
+{
+	enum snet_verdict verdict = SNET_VERDICT_NONE;
+	u8 protocol = 0;
+
+	if (snet_check_listeners(&verdict) < 0)
+		goto out;
+
+	protocol = sock->sk->sk_protocol;
+
+	if (snet_event_is_registered(SNET_SOCKET_CONNECT, protocol)) {
+		struct snet_info info;
+		struct inet_sock *inet = inet_sk(sock->sk);
+		struct sockaddr_in *a = (struct sockaddr_in *) address;
+		struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) address;
+
+		/* prepare networking informations for userspace */
+		memset(&info, 0, sizeof(struct  snet_info));
+		info.syscall = SNET_SOCKET_CONNECT;
+		info.protocol = protocol;
+		info.family = sock->sk->sk_family;
+		info.src.u.port = ntohs(inet->inet_sport);
+
+		switch (sock->sk->sk_family) {
+		case PF_INET:
+			info.src.u3.ip = inet->inet_saddr;
+			info.dst.u3.ip = a->sin_addr.s_addr;
+			info.dst.u.port = ntohs(a->sin_port);
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		case PF_INET6:
+			memcpy(&info.src.u3.ip6, (void *)&inet->pinet6->saddr,
+			       sizeof(info.src.u3.ip6));
+			memcpy(&info.dst.u3.ip6, (void *)&a6->sin6_addr,
+			       sizeof(info.dst.u3.ip6));
+			info.dst.u.port = ntohs(a6->sin6_port);
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#endif
+		default:
+			verdict = SNET_VERDICT_NONE;
+			goto skip_send_wait;
+			break;
+		}
+		snet_pr_tuple(&info);
+		snet_do_verdict(&verdict, &info);
+		/* create ticket */
+		snet_ticket_create(&info, verdict);
+	} else {
+		verdict = SNET_VERDICT_GRANT;
+	}
+
+skip_send_wait:
+	if (verdict == SNET_VERDICT_NONE)
+		verdict = snet_verdict_policy;
+out:
+	return verdict;
+}
+
+static int snet_socket_listen(struct socket *sock, int backlog)
+{
+	enum snet_verdict verdict = SNET_VERDICT_NONE;
+	u8 protocol = 0;
+
+	if (snet_check_listeners(&verdict) < 0)
+		goto out;
+
+	protocol = sock->sk->sk_protocol;
+
+	if (snet_event_is_registered(SNET_SOCKET_LISTEN, protocol)) {
+		struct snet_info info;
+		struct inet_sock *inet = inet_sk(sock->sk);
+
+		/* prepare networking informations for userspace */
+		memset(&info, 0, sizeof(struct  snet_info));
+		info.syscall = SNET_SOCKET_LISTEN;
+		info.protocol = protocol;
+		info.family = sock->sk->sk_family;
+		info.src.u.port = ntohs(inet->inet_sport);
+		info.dst.u.port = ntohs(inet->inet_dport);
+
+		switch (sock->sk->sk_family) {
+		case PF_INET:
+			info.src.u3.ip = inet->inet_saddr;
+			info.dst.u3.ip = inet->inet_daddr;
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		case PF_INET6:
+			memcpy(&info.src.u3.ip6, (void *)&inet->pinet6->saddr,
+			       sizeof(info.src.u3.ip6));
+			memcpy(&info.dst.u3.ip6, (void *)&inet->pinet6->daddr,
+			       sizeof(info.dst.u3.ip6));
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#endif
+		default:
+			verdict = SNET_VERDICT_NONE;
+			goto skip_send_wait;
+			break;
+		}
+		snet_pr_tuple(&info);
+		snet_do_verdict(&verdict, &info);
+		/* create ticket */
+		snet_ticket_create(&info, verdict);
+	} else {
+		verdict = SNET_VERDICT_GRANT;
+	}
+
+skip_send_wait:
+	if (verdict == SNET_VERDICT_NONE)
+		verdict = snet_verdict_policy;
+out:
+	return verdict;
+}
+
+static int snet_socket_accept(struct socket *sock, struct socket *newsock)
+{
+	enum snet_verdict verdict = SNET_VERDICT_NONE;
+	u8 protocol = 0;
+
+	if (snet_check_listeners(&verdict) < 0)
+		goto out;
+
+	protocol = sock->sk->sk_protocol;
+
+	if (snet_event_is_registered(SNET_SOCKET_ACCEPT, protocol)) {
+		struct snet_info info;
+		struct inet_sock *inet = inet_sk(sock->sk);
+
+		/* prepare networking informations for userspace */
+		info.syscall = SNET_SOCKET_ACCEPT;
+		info.protocol = protocol;
+		info.family = sock->sk->sk_family;
+		info.src.u.port = ntohs(inet->inet_sport);
+		info.dst.u.port = ntohs(inet->inet_dport);
+
+		switch (sock->sk->sk_family) {
+		case PF_INET:
+			info.src.u3.ip = inet->inet_saddr;
+			info.dst.u3.ip = inet->inet_daddr;
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		case PF_INET6:
+			memcpy(&info.src.u3.ip6, (void *)&inet->pinet6->saddr,
+			       sizeof(info.src.u3.ip6));
+			memcpy(&info.dst.u3.ip6, (void *)&inet->pinet6->daddr,
+			       sizeof(info.dst.u3.ip6));
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#endif
+		default:
+			verdict = SNET_VERDICT_NONE;
+			goto skip_send_wait;
+			break;
+		}
+		snet_pr_tuple(&info);
+		snet_do_verdict(&verdict, &info);
+		/* create ticket */
+		snet_ticket_create(&info, verdict);
+	} else {
+		verdict = SNET_VERDICT_GRANT;
+	}
+
+skip_send_wait:
+	if (verdict == SNET_VERDICT_NONE)
+		verdict = snet_verdict_policy;
+out:
+	return verdict;
+}
+
+static void snet_socket_post_accept(struct socket *sock, struct socket *newsock)
+{
+	u8 protocol = 0;
+
+	if (snet_check_listeners(NULL)  < 0)
+		goto out;
+
+	protocol = sock->sk->sk_protocol;
+
+	if (snet_event_is_registered(SNET_SOCKET_POST_ACCEPT, protocol)) {
+		struct snet_info info;
+		struct inet_sock *inet = inet_sk(newsock->sk);
+
+		/* prepare networking informations for userspace */
+		info.syscall = SNET_SOCKET_POST_ACCEPT;
+		info.protocol = protocol;
+		info.family = sock->sk->sk_family;
+		info.verdict_id = 0;
+		info.src.u.port = ntohs(inet->inet_sport);
+		info.dst.u.port = ntohs(inet->inet_dport);
+
+		switch (sock->sk->sk_family) {
+		case PF_INET:
+			info.src.u3.ip = inet->inet_saddr;
+			info.dst.u3.ip = inet->inet_daddr;
+			break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		case PF_INET6:
+			memcpy(&info.src.u3.ip6, (void *)&inet->pinet6->saddr,
+			       sizeof(info.src.u3.ip6));
+			memcpy(&info.dst.u3.ip6, (void *)&inet->pinet6->daddr,
+			       sizeof(info.dst.u3.ip6));
+			break;
+#endif
+		default:
+			goto out;
+			break;
+		}
+		snet_pr_tuple(&info);
+		snet_do_send_event(&info);
+	}
+out:
+	return;
+}
+
+static int snet_socket_sendmsg(struct socket *sock,
+			       struct msghdr *msg, int size)
+{
+	enum snet_verdict verdict = SNET_VERDICT_NONE;
+	u8 protocol = 0;
+
+	if (snet_check_listeners(&verdict) < 0)
+		goto out;
+
+	protocol = sock->sk->sk_protocol;
+
+	if (snet_event_is_registered(SNET_SOCKET_SENDMSG, protocol)) {
+		struct snet_info info;
+		struct inet_sock *inet = inet_sk(sock->sk);
+
+		/* prepare networking informations for userspace */
+		info.syscall = SNET_SOCKET_SENDMSG;
+		info.protocol = protocol;
+		info.family = sock->sk->sk_family;
+		info.src.u.port = ntohs(inet->inet_sport);
+		info.dst.u.port = ntohs(inet->inet_dport);
+		info.len = size;
+		info.buffer = msg->msg_iov->iov_base;
+
+		switch (sock->sk->sk_family) {
+		case PF_INET:
+			info.src.u3.ip = inet->inet_saddr;
+			info.dst.u3.ip = inet->inet_daddr;
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		case PF_INET6:
+			memcpy(&info.src.u3.ip6, (void *)&inet->pinet6->saddr,
+			       sizeof(info.src.u3.ip6));
+			memcpy(&info.dst.u3.ip6, (void *)&inet->pinet6->daddr,
+			       sizeof(info.dst.u3.ip6));
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#endif
+		default:
+			verdict = SNET_VERDICT_NONE;
+			goto skip_send_wait;
+			break;
+		}
+		snet_pr_tuple(&info);
+		snet_do_verdict(&verdict, &info);
+		/* create ticket */
+		snet_ticket_create(&info, verdict);
+	} else {
+		verdict = SNET_VERDICT_GRANT;
+	}
+
+skip_send_wait:
+	if (verdict == SNET_VERDICT_NONE)
+		verdict = snet_verdict_policy;
+out:
+	return verdict;
+}
+
+static int snet_socket_recvmsg(struct socket *sock,
+			       struct msghdr *msg, int size, int flags)
+{
+	enum snet_verdict verdict = SNET_VERDICT_NONE;
+	u8 protocol = 0;
+
+	if (snet_check_listeners(&verdict) < 0)
+		goto out;
+
+	protocol = sock->sk->sk_protocol;
+
+	if (snet_event_is_registered(SNET_SOCKET_RECVMSG, protocol)) {
+		struct snet_info info;
+		struct inet_sock *inet = inet_sk(sock->sk);
+
+		/* prepare networking informations for userspace */
+		info.syscall = SNET_SOCKET_RECVMSG;
+		info.protocol = protocol;
+		info.family = sock->sk->sk_family;
+		info.src.u.port = ntohs(inet->inet_sport);
+		info.dst.u.port = ntohs(inet->inet_dport);
+
+		switch (sock->sk->sk_family) {
+		case PF_INET:
+			info.src.u3.ip = inet->inet_saddr;
+			info.dst.u3.ip = inet->inet_daddr;
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		case PF_INET6:
+			memcpy(&info.src.u3.ip6, (void *)&inet->pinet6->saddr,
+			       sizeof(info.src.u3.ip6));
+			memcpy(&info.dst.u3.ip6, (void *)&inet->pinet6->daddr,
+			       sizeof(info.dst.u3.ip6));
+			/* check tickets */
+			if ((verdict = snet_ticket_check(&info)) != SNET_VERDICT_NONE)
+				goto out;
+			/* inserting verdict PENDING */
+			info.verdict_id = snet_verdict_insert();
+			break;
+#endif
+		default:
+			verdict = SNET_VERDICT_NONE;
+			goto skip_send_wait;
+			break;
+		}
+		snet_pr_tuple(&info);
+		snet_do_verdict(&verdict, &info);
+		/* create ticket */
+		snet_ticket_create(&info, verdict);
+	} else {
+		verdict = SNET_VERDICT_GRANT;
+	}
+
+skip_send_wait:
+	if (verdict == SNET_VERDICT_NONE)
+		verdict = snet_verdict_policy;
+out:
+	return verdict;
+}
+
+static int snet_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+	enum snet_verdict verdict = SNET_VERDICT_NONE;
+	u8 protocol = 0;
+
+	if (snet_check_listeners(&verdict) < 0)
+		goto out;
+
+	protocol = sk->sk_protocol;
+
+	if (snet_event_is_registered(SNET_SOCKET_SOCK_RCV_SKB, protocol)) {
+		struct snet_info info;
+		struct inet_sock *inet = inet_sk(sk);
+
+		/* prepare networking informations for userspace */
+		info.syscall = SNET_SOCKET_SOCK_RCV_SKB;
+		info.protocol = protocol;
+		info.family = sk->sk_family;
+		info.src.u.port = ntohs(inet->inet_sport);
+		info.dst.u.port = ntohs(inet->inet_dport);
+
+		switch (sk->sk_family) {
+		case PF_INET:
+			/* inserting verdict PENDING  */
+			/* info.verdict_id = snet_verdict_insert(); */
+
+			info.src.u3.ip = inet->inet_saddr;
+			info.dst.u3.ip = inet->inet_daddr;
+			break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		case PF_INET6:
+			/* inserting verdict PENDING  */
+			/* info.verdict_id = snet_verdict_insert(); */
+
+			memcpy(&info.src.u3.ip6, (void *)&inet->pinet6->saddr,
+			       sizeof(info.src.u3.ip6));
+			memcpy(&info.dst.u3.ip6, (void *)&inet->pinet6->daddr,
+			       sizeof(info.dst.u3.ip6));
+			break;
+#endif
+		default:
+			verdict = SNET_VERDICT_NONE;
+			goto skip_send_wait;
+			break;
+		}
+		snet_pr_tuple(&info);
+		/* SNET_DOC_VERDICT(info); */
+	} else {
+		verdict = SNET_VERDICT_GRANT;
+	}
+
+skip_send_wait:
+	if (verdict == SNET_VERDICT_NONE)
+		verdict = snet_verdict_policy;
+out:
+	return verdict;
+}
+
+static void snet_socket_close(struct socket *sock)
+{
+	u8 protocol = 0;
+
+	if (sock == NULL || sock->sk == NULL) {
+		goto out;
+	}
+
+	if (snet_check_listeners(NULL)  < 0)
+		goto out;
+
+	protocol = sock->sk->sk_protocol;
+
+	if (snet_event_is_registered(SNET_SOCKET_CLOSE, protocol)) {
+		struct snet_info info;
+		struct inet_sock *inet = inet_sk(sock->sk);
+
+		/* prepare networking informations for userspace */
+		info.syscall = SNET_SOCKET_CLOSE;
+		info.protocol = protocol;
+		info.family = sock->sk->sk_family;
+		info.verdict_id = 0;
+		info.src.u.port = ntohs(inet->inet_sport);
+		info.dst.u.port = ntohs(inet->inet_dport);
+
+		switch (sock->sk->sk_family) {
+		case PF_INET:
+			info.src.u3.ip = inet->inet_saddr;
+			info.dst.u3.ip = inet->inet_daddr;
+			break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+		case PF_INET6:
+			memcpy(&info.src.u3.ip6, (void *)&inet->pinet6->saddr,
+			       sizeof(info.src.u3.ip6));
+			memcpy(&info.dst.u3.ip6, (void *)&inet->pinet6->daddr,
+			       sizeof(info.dst.u3.ip6));
+			break;
+#endif
+		default:
+			goto out;
+			break;
+		}
+		snet_pr_tuple(&info);
+		snet_do_send_event(&info);
+	}
+out:
+	return;
+}
+
+static struct security_operations snet_security_ops = {
+	.name			= "snet",
+
+	.socket_create		= snet_socket_create,
+	.socket_bind		= snet_socket_bind,
+	.socket_connect		= snet_socket_connect,
+	.socket_listen		= snet_socket_listen,
+	.socket_accept		= snet_socket_accept,
+	.socket_post_accept	= snet_socket_post_accept,
+	.socket_sendmsg		= snet_socket_sendmsg,
+	.socket_recvmsg		= snet_socket_recvmsg,
+	.socket_sock_rcv_skb	= snet_socket_sock_rcv_skb,
+	.socket_close		= snet_socket_close,
+
+	.cred_prepare		= snet_prepare_creds,
+	.cred_free		= snet_cred_free,
+};
+
+int snet_hooks_init(void)
+{
+	if (!security_module_enable(&snet_security_ops))
+		return 0;
+
+	if (register_security(&snet_security_ops))
+		panic("snet: failed to register security_ops\n");
+
+	return 0;
+}
diff --git a/security/snet/snet_hooks.h b/security/snet/snet_hooks.h
new file mode 100644
index 0000000..05fe5e8
--- /dev/null
+++ b/security/snet/snet_hooks.h
@@ -0,0 +1,10 @@
+#ifndef _SNET_HOOKS_H
+#define _SNET_HOOKS_H
+
+extern uint32_t snet_nl_pid;
+extern unsigned int snet_verdict_policy;
+
+/* init function */
+int snet_hooks_init(void);
+
+#endif /* _SNET_HOOK_H */
-- 
1.6.3.3

^ permalink raw reply related

* [RFC v2 07/10] snet: introduce snet_netlink
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

this patch adds the snet communication's subsystem.

snet_netlink is using genetlink for sending/receiving messages to/from userspace.
the genetlink operations permit to receive orders to manage the list of events
- events are values [syscall, protocol] - which is used to know which syscall
and protocol have to be protected. genl operations are also used to manage
communication of events to userspace, and to receive the related verdict.

Signed-off-by: Samir Bellabes <sam@synack.fr>
---
 security/snet/snet_netlink.c        |  431 +++++++++++++++++++++++++++++++++++
 security/snet/snet_netlink.h        |   17 ++
 security/snet/snet_netlink_helper.c |  230 +++++++++++++++++++
 security/snet/snet_netlink_helper.h |    7 +
 4 files changed, 685 insertions(+), 0 deletions(-)
 create mode 100644 security/snet/snet_netlink.c
 create mode 100644 security/snet/snet_netlink.h
 create mode 100644 security/snet/snet_netlink_helper.c
 create mode 100644 security/snet/snet_netlink_helper.h

diff --git a/security/snet/snet_netlink.c b/security/snet/snet_netlink.c
new file mode 100644
index 0000000..b0dd163
--- /dev/null
+++ b/security/snet/snet_netlink.c
@@ -0,0 +1,431 @@
+#include <linux/sched.h>
+#include <net/genetlink.h>
+#include <linux/in6.h>
+#include <linux/snet.h>
+#include "snet_netlink.h"
+#include "snet_netlink_helper.h"
+#include "snet_verdict.h"
+#include "snet_event.h"
+#include "snet_utils.h"
+
+atomic_t snet_nl_seq = ATOMIC_INIT(0);
+uint32_t snet_nl_pid;
+static struct genl_family snet_genl_family;
+
+/*
+ * snet genetlink
+ */
+int snet_nl_send_event(struct snet_info *info)
+{
+	struct sk_buff *skb_rsp;
+	void *msg_head;
+	int ret = 0, sbs = -1;
+	size_t size = 0;
+
+	sbs = snet_nl_size_by_syscall(info);
+	if (sbs < 0)
+		return -EINVAL;
+
+	size =  sbs +
+		2 * nla_total_size(sizeof(u8)) +
+		1 * nla_total_size(sizeof(u16)) +
+		(info->verdict_id ? 3 : 2) * nla_total_size(sizeof(u32));
+
+	skb_rsp = genlmsg_new(size, GFP_KERNEL);
+	if (skb_rsp == NULL)
+		return -ENOMEM;
+
+	msg_head = genlmsg_put(skb_rsp, snet_nl_pid,
+			       atomic_inc_return(&snet_nl_seq),
+			       &snet_genl_family, 0, SNET_C_VERDICT);
+	if (msg_head == NULL)
+		goto nla_put_failure;
+
+	pr_debug("verdict_id=0x%x syscall=%s protocol=%u "
+		 "family=%u uid=%u pid=%u\n",
+		 info->verdict_id, snet_syscall_name(info->syscall),
+		 info->protocol, info->family, current_uid(), current->pid);
+
+	if (info->verdict_id)
+		NLA_PUT_U32(skb_rsp, SNET_A_VERDICT_ID, info->verdict_id);
+	NLA_PUT_U16(skb_rsp, SNET_A_SYSCALL, info->syscall);
+	NLA_PUT_U8(skb_rsp, SNET_A_PROTOCOL, info->protocol);
+	NLA_PUT_U8(skb_rsp, SNET_A_FAMILY, info->family);
+	NLA_PUT_U32(skb_rsp, SNET_A_UID, current_uid());
+	NLA_PUT_U32(skb_rsp, SNET_A_PID, current->pid);
+
+	ret = snet_nl_fill_by_syscall(skb_rsp, info);
+	if (ret != 0)
+		goto nla_put_failure;
+
+	ret = genlmsg_end(skb_rsp, msg_head);
+	if (ret < 0)
+		goto nla_put_failure;
+
+	return genlmsg_unicast(&init_net, skb_rsp, snet_nl_pid);
+
+nla_put_failure:
+	kfree_skb(skb_rsp);
+	return -ECONNABORTED;
+}
+
+/*
+ * snet genetlink functions
+ */
+
+static struct genl_family snet_genl_family = {
+	.id		= GENL_ID_GENERATE,
+	.hdrsize	= 0,
+	.name		= SNET_GENL_NAME,
+	.version	= SNET_GENL_VERSION,
+	.maxattr	= SNET_A_MAX,
+};
+
+static const struct nla_policy snet_genl_policy[SNET_A_MAX + 1] = {
+	[SNET_A_VERSION]		= { .type = NLA_U32 },
+	[SNET_A_VERDICT_ID]		= { .type = NLA_U32 },
+	[SNET_A_FAMILY]			= { .type = NLA_U8 },
+	[SNET_A_SYSCALL]		= { .type = NLA_U16 },
+	[SNET_A_PROTOCOL]		= { .type = NLA_U8 },
+	[SNET_A_UID]			= { .type = NLA_U32 },
+	[SNET_A_PID]			= { .type = NLA_U32 },
+	[SNET_A_TYPE]			= { .type = NLA_U32 },
+	[SNET_A_IPV4SADDR]		= { .type = NLA_BINARY,
+					    .len = sizeof(struct in_addr) },
+	[SNET_A_IPV6SADDR]		= { .type = NLA_BINARY,
+					    .len = sizeof(struct in6_addr) },
+	[SNET_A_IPV4DADDR]		= { .type = NLA_BINARY,
+					    .len = sizeof(struct in_addr) },
+	[SNET_A_IPV6DADDR]		= { .type = NLA_BINARY,
+					    .len = sizeof(struct in6_addr) },
+	[SNET_A_BUFFER]			= { .type = NLA_BINARY },
+	[SNET_A_BUFFER_LEN]		= { .type = NLA_U32 },
+	[SNET_A_SPORT]			= { .type = NLA_U16 },
+	[SNET_A_DPORT]			= { .type = NLA_U16 },
+	[SNET_A_VERDICT]		= { .type = NLA_U8 },
+	[SNET_A_VERDICT_DELAY]		= { .type = NLA_U32 },
+	[SNET_A_TICKET_DELAY]		= { .type = NLA_U32 },
+	[SNET_A_TICKET_MODE]		= { .type = NLA_U8 },
+};
+
+/**
+ * snet_nl_version - Handle a VERSION message
+ * @skb: the NETLINK buffer
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Process a user generated VERSION message and respond accordingly.
+ * Returns zero on success, negative values on failure.
+ */
+static int snet_nl_version(struct sk_buff *skb, struct genl_info *info)
+{
+	int ret = 0;
+	struct sk_buff *skb_rsp = NULL;
+	void *msg_head;
+
+	atomic_set(&snet_nl_seq, info->snd_seq);
+
+	skb_rsp = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (skb_rsp == NULL)
+		return -ENOMEM;
+	msg_head = genlmsg_put_reply(skb_rsp, info, &snet_genl_family,
+				     0, SNET_C_VERSION);
+	if (msg_head == NULL)
+		goto nla_put_failure;
+
+	NLA_PUT_U32(skb_rsp, SNET_A_VERSION, SNET_VERSION);
+
+	ret = genlmsg_end(skb_rsp, msg_head);
+	if (ret < 0)
+		goto nla_put_failure;
+
+	ret = genlmsg_reply(skb_rsp, info);
+	if (ret != 0)
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	kfree_skb(skb_rsp);
+	return ret;
+}
+
+/**
+ * snet_nl_register - Handle a REGISTER message
+ * @skb: the NETLINK buffer
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Notify the kernel that an application is listening for events.
+ * Returns zero on success, negative values on failure.
+ */
+static int snet_nl_register(struct sk_buff *skb, struct genl_info *info)
+{
+	int ret = 0;
+	u32 version = 0;
+
+	atomic_set(&snet_nl_seq, info->snd_seq);
+
+	if (!info->attrs[SNET_A_VERSION]) {
+		ret = -EINVAL;
+		goto out;
+	}
+	version = nla_get_u32(info->attrs[SNET_A_VERSION]);
+
+	if (version != SNET_VERSION) {
+		ret = -EPERM;
+		goto out;
+	}
+
+	if (snet_nl_pid > 0) {
+		ret = -ECONNREFUSED;
+		goto out;
+	}
+	snet_nl_pid = info->snd_pid;
+	pr_debug("pid=%u\n", snet_nl_pid);
+out:
+	return ret;
+}
+
+/**
+ * snet_nl_unregister - Handle a UNREGISTER message
+ * @skb: the NETLINK buffer
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Notify the kernel that the application is no more listening for events.
+ * Returns zero on success, negative values on failure.
+ */
+static int snet_nl_unregister(struct sk_buff *skb, struct genl_info *info)
+{
+	int ret = 0;
+
+	atomic_set(&snet_nl_seq, info->snd_seq);
+
+	if (snet_nl_pid == 0) {
+		ret = -ENOTCONN;
+		goto out;
+	}
+
+	snet_nl_pid = 0;
+	pr_debug("pid=%u\n", snet_nl_pid);
+out:
+	return ret;
+}
+
+/**
+ * snet_nl_insert - Handle a INSERT message
+ * @skb: the NETLINK buffer
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Insert a new event to the events' hashtable. Returns zero on success,
+ * negative values on failure.
+ */
+static int snet_nl_insert(struct sk_buff *skb, struct genl_info *info)
+{
+	int ret = 0;
+	enum snet_syscall syscall;
+	u8 protocol;
+
+	atomic_set(&snet_nl_seq, info->snd_seq);
+
+	if (!info->attrs[SNET_A_SYSCALL] || !info->attrs[SNET_A_PROTOCOL]) {
+		ret =  -EINVAL;
+		goto out;
+	}
+	syscall = nla_get_u16(info->attrs[SNET_A_SYSCALL]);
+	protocol = nla_get_u8(info->attrs[SNET_A_PROTOCOL]);
+	ret = snet_event_insert(syscall, protocol);
+	pr_debug("syscall=%s protocol=%u insert=%s\n",
+		 snet_syscall_name(syscall), protocol,
+		 (ret == 0) ? "success" : "failed");
+out:
+	return ret;
+}
+
+/**
+ * snet_nl_remove - Handle a REMOVE message
+ * @skb: the NETLINK buffer
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Remove a event from the events' hastable. Returns zero on success,
+ * negative values on failure.
+ */
+static int snet_nl_remove(struct sk_buff *skb, struct genl_info *info)
+{
+	int ret = 0;
+	enum snet_syscall syscall;
+	u8 protocol;
+
+	atomic_set(&snet_nl_seq, info->snd_seq);
+
+	if (!info->attrs[SNET_A_SYSCALL] || !info->attrs[SNET_A_PROTOCOL]) {
+		ret = -EINVAL;
+		goto out;
+	}
+	syscall = nla_get_u16(info->attrs[SNET_A_SYSCALL]);
+	protocol = nla_get_u8(info->attrs[SNET_A_PROTOCOL]);
+	ret = snet_event_remove(syscall, protocol);
+	pr_debug("syscall=%s protocol=%u remove=%s\n",
+		 snet_syscall_name(syscall), protocol,
+		 (ret == 0) ? "success" : "failed");
+out:
+	return ret;
+}
+
+/**
+ * snet_nl_flush - Handle a FLUSH message
+ * @skb: the NETLINK buffer
+ * @info: the Generic NETLINK info block
+ *
+ * Description:
+ * Remove all events from the hashtable. Returns zero on success,
+ * negative values on failure.
+ */
+static int snet_nl_flush(struct sk_buff *skb, struct genl_info *info)
+{
+	atomic_set(&snet_nl_seq, info->snd_seq);
+	snet_event_flush();
+	return 0;
+}
+
+int snet_nl_list_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
+			   u32 flags, u8 protocol, enum snet_syscall syscall)
+{
+	void *hdr;
+
+	hdr = genlmsg_put(skb, pid, seq, &snet_genl_family, flags, SNET_C_LIST);
+	if (hdr == NULL)
+		return -1;
+
+	NLA_PUT_U16(skb, SNET_A_SYSCALL, syscall);
+	NLA_PUT_U8(skb, SNET_A_PROTOCOL, protocol);
+
+	return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+/**
+ * snet_nl_list - Handle a LIST message
+ * @skb: the NETLINK buffer
+ * @cb:
+ *
+ * Description:
+ * Process a user LIST message and respond. Returns zero on success,
+ * and negative values on error.
+ */
+static int snet_nl_list(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	unsigned int len = 0;
+
+	atomic_set(&snet_nl_seq, cb->nlh->nlmsg_seq);
+	len = snet_event_fill_info(skb, cb);
+	return len;
+}
+
+/**
+ * snet_nl_verdict - Handle a VERDICT message
+ * @skb: the NETLINK buffer
+ * @info the Generic NETLINK info block
+ *
+ * Description:
+ * Provides userspace with a VERDICT message, ie we are sending informations
+ * with this command. Userspace is sending the appropriate verdict for the
+ * event. Returns zero on success,and negative values on error.
+ */
+static int snet_nl_verdict(struct sk_buff *skb, struct genl_info *info)
+{
+	int ret = 0;
+	u32 verdict_id;
+	enum snet_verdict verdict;
+
+	atomic_set(&snet_nl_seq, info->snd_seq);
+
+	if (snet_nl_pid == 0) {
+		ret = -ENOTCONN;
+		goto out;
+	}
+
+	if (!info->attrs[SNET_A_VERDICT_ID] || !info->attrs[SNET_A_VERDICT]) {
+		ret = -EINVAL;
+		goto out;
+	}
+	verdict_id = nla_get_u32(info->attrs[SNET_A_VERDICT_ID]);
+	verdict = nla_get_u8(info->attrs[SNET_A_VERDICT]);
+	ret = snet_verdict_set(verdict_id, verdict);
+out:
+	return ret;
+}
+
+static int snet_nl_config(struct sk_buff *skb,
+			  struct genl_info *info)
+{
+	int ret = -EINVAL;
+
+	atomic_set(&snet_nl_seq, info->snd_seq);
+
+	if (info->attrs[SNET_A_VERDICT_DELAY]) {
+		snet_verdict_delay = nla_get_u32(info->attrs[SNET_A_VERDICT_DELAY]);
+		pr_debug("snet_nl_config: verdict_delay=%u\n", snet_verdict_delay);
+		ret = 0;
+	}
+	if (info->attrs[SNET_A_TICKET_DELAY]) {
+		snet_ticket_delay = nla_get_u32(info->attrs[SNET_A_TICKET_DELAY]);
+		pr_debug("snet_nl_config: ticket_delay=%u\n", snet_ticket_delay);
+		ret = 0;
+	}
+	if (info->attrs[SNET_A_TICKET_MODE]) {
+		snet_ticket_mode = nla_get_u32(info->attrs[SNET_A_TICKET_MODE]);
+		pr_debug("snet_nl_config: ticket_mode=%u\n", snet_ticket_mode);
+		ret = 0;
+	}
+	return ret;
+}
+
+#define SNET_GENL_OPS(_cmd, _flags, _policy, _op, _opname)	\
+	{							\
+		.cmd	= _cmd,					\
+		.flags	= _flags,				\
+		.policy	= _policy,				\
+		._op	= snet_nl_##_opname,			\
+	}
+
+static struct genl_ops snet_genl_ops[] = {
+	SNET_GENL_OPS(SNET_C_VERSION, GENL_ADMIN_PERM, snet_genl_policy,
+		      doit, version),
+	SNET_GENL_OPS(SNET_C_REGISTER, GENL_ADMIN_PERM, snet_genl_policy,
+		      doit, register),
+	SNET_GENL_OPS(SNET_C_UNREGISTER, GENL_ADMIN_PERM, snet_genl_policy,
+		      doit, unregister),
+	SNET_GENL_OPS(SNET_C_INSERT, GENL_ADMIN_PERM, snet_genl_policy,
+		      doit, insert),
+	SNET_GENL_OPS(SNET_C_REMOVE, GENL_ADMIN_PERM, snet_genl_policy,
+		      doit, remove),
+	SNET_GENL_OPS(SNET_C_FLUSH, GENL_ADMIN_PERM, snet_genl_policy,
+		      doit, flush),
+	SNET_GENL_OPS(SNET_C_LIST, GENL_ADMIN_PERM, snet_genl_policy,
+		      dumpit, list),
+	SNET_GENL_OPS(SNET_C_VERDICT, GENL_ADMIN_PERM, snet_genl_policy,
+		      doit, verdict),
+	SNET_GENL_OPS(SNET_C_CONFIG, GENL_ADMIN_PERM, snet_genl_policy,
+		      doit, config),
+};
+
+#undef SNET_GENL_OPS
+
+static __init int snet_netlink_init(void)
+{
+	return genl_register_family_with_ops(&snet_genl_family,
+					     snet_genl_ops,
+					     ARRAY_SIZE(snet_genl_ops));
+}
+
+void snet_netlink_exit(void)
+{
+	genl_unregister_family(&snet_genl_family);
+}
+
+__initcall(snet_netlink_init);
diff --git a/security/snet/snet_netlink.h b/security/snet/snet_netlink.h
new file mode 100644
index 0000000..5e80d7b
--- /dev/null
+++ b/security/snet/snet_netlink.h
@@ -0,0 +1,17 @@
+#ifndef _SNET_NETLINK_H
+#define _SNET_NETLINK_H
+
+#include <linux/in6.h>
+
+extern unsigned int snet_verdict_delay;
+extern unsigned int snet_ticket_delay;
+extern unsigned int snet_ticket_mode;
+
+int snet_nl_send_event(struct snet_info *info);
+
+int snet_nl_list_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
+			   u32 flags, u8 protocol, enum snet_syscall syscall);
+
+void snet_netlink_exit(void);
+
+#endif /* _SNET_NETLINK_H */
diff --git a/security/snet/snet_netlink_helper.c b/security/snet/snet_netlink_helper.c
new file mode 100644
index 0000000..d6b5343
--- /dev/null
+++ b/security/snet/snet_netlink_helper.c
@@ -0,0 +1,230 @@
+#include <net/netlink.h>
+#include <net/genetlink.h>
+#include <linux/in6.h>
+#include <linux/snet.h>
+
+static int fill_src(struct sk_buff *skb_rsp, struct snet_info *info)
+{
+	int ret;
+	switch (info->family) {
+	case PF_INET:
+		ret = nla_put(skb_rsp, SNET_A_IPV4SADDR,
+			      sizeof(struct in_addr), &(info->src.u3.ip));
+		if (ret != 0)
+			goto out;
+		break;
+	case PF_INET6:
+		ret = nla_put(skb_rsp, SNET_A_IPV6SADDR,
+			      sizeof(struct in6_addr), &(info->src.u3.ip6));
+		if (ret != 0)
+			goto out;
+		break;
+	default:
+		break;
+	}
+	ret = nla_put_u16(skb_rsp, SNET_A_SPORT, info->src.u.port);
+out:
+	return ret;
+
+}
+
+static int fill_dst(struct sk_buff *skb_rsp, struct snet_info *info)
+{
+	int ret;
+	switch (info->family) {
+	case PF_INET:
+		ret = nla_put(skb_rsp, SNET_A_IPV4DADDR,
+			      sizeof(struct in_addr), &(info->dst.u3.ip));
+		if (ret != 0)
+			goto out;
+		break;
+	case PF_INET6:
+		ret = nla_put(skb_rsp, SNET_A_IPV6DADDR,
+			      sizeof(struct in6_addr), &(info->dst.u3.ip6));
+		if (ret != 0)
+			goto out;
+		break;
+	default:
+		break;
+	}
+	ret = nla_put_u16(skb_rsp, SNET_A_DPORT, info->dst.u.port);
+out:
+	return ret;
+}
+
+static int snet_fill_create(struct sk_buff *skb_rsp, struct snet_info *info)
+{
+	int ret;
+	ret = nla_put_u8(skb_rsp, SNET_A_TYPE, info->type);
+	return ret;
+}
+
+static int snet_fill_bind(struct sk_buff *skb_rsp,  struct snet_info *info)
+{
+	return fill_src(skb_rsp, info);
+}
+
+static int snet_fill_connect(struct sk_buff *skb_rsp, struct snet_info *info)
+{
+	int ret;
+
+	ret = fill_src(skb_rsp, info);
+	if (ret != 0)
+		goto out;
+	ret = fill_dst(skb_rsp, info);
+out:
+	return ret;
+}
+
+static int snet_fill_listen(struct sk_buff *skb_rsp, struct snet_info *info)
+{
+	return fill_src(skb_rsp, info);
+}
+
+static int snet_fill_accept(struct sk_buff *skb_rsp, struct snet_info *info)
+{
+	return fill_src(skb_rsp, info);
+}
+
+static int snet_fill_post_accept(struct sk_buff *skb_rsp,
+				 struct snet_info *info)
+{
+	int ret;
+
+	ret = fill_src(skb_rsp, info);
+	if (ret != 0)
+		goto out;
+	ret = fill_dst(skb_rsp, info);
+out:
+	return ret;
+}
+
+static int snet_fill_sendmsg(struct sk_buff *skb_rsp, struct snet_info *info)
+{
+	int ret;
+
+	ret = fill_src(skb_rsp, info);
+	if (ret != 0)
+		goto out;
+	ret = fill_dst(skb_rsp, info);
+	if (ret != 0)
+		goto out;
+	ret = nla_put(skb_rsp, SNET_A_BUFFER, info->len, info->buffer);
+	if (ret != 0)
+		goto out;
+	ret = nla_put_u32(skb_rsp, SNET_A_BUFFER_LEN, info->len);
+out:
+	return ret;
+}
+
+static int snet_fill_recvmsg(struct sk_buff *skb_rsp, struct snet_info *info)
+{
+	int ret;
+
+	ret = fill_src(skb_rsp, info);
+	if (ret != 0)
+		goto out;
+	ret = fill_dst(skb_rsp, info);
+out:
+	return ret;
+}
+
+static int snet_fill_sock_rcv_skb(struct sk_buff *skb_rsp,
+				  struct snet_info *info)
+{
+	int ret;
+
+	ret = fill_src(skb_rsp, info);
+	if (ret != 0)
+		goto out;
+	ret = fill_dst(skb_rsp, info);
+out:
+	return ret;
+}
+
+static int snet_fill_close(struct sk_buff *skb_rsp, struct snet_info *info)
+{
+	int ret;
+
+	ret = fill_src(skb_rsp, info);
+	if (ret != 0)
+		goto out;
+	ret = fill_dst(skb_rsp, info);
+out:
+	return ret;
+}
+
+int snet_nl_fill_by_syscall(struct sk_buff *skb_rsp, struct snet_info *info)
+{
+	static int (*snet_df[])(struct sk_buff *, struct snet_info *) = {
+		[SNET_SOCKET_CREATE]		= &snet_fill_create,
+		[SNET_SOCKET_BIND]		= &snet_fill_bind,
+		[SNET_SOCKET_CONNECT]		= &snet_fill_connect,
+		[SNET_SOCKET_LISTEN]		= &snet_fill_listen,
+		[SNET_SOCKET_ACCEPT]		= &snet_fill_accept,
+		[SNET_SOCKET_POST_ACCEPT]	= &snet_fill_post_accept,
+		[SNET_SOCKET_SENDMSG]		= &snet_fill_sendmsg,
+		[SNET_SOCKET_RECVMSG]		= &snet_fill_recvmsg,
+		[SNET_SOCKET_SOCK_RCV_SKB]	= &snet_fill_sock_rcv_skb,
+		[SNET_SOCKET_CLOSE]		= &snet_fill_close,
+	};
+
+	if (info->syscall >= SNET_NR_SOCKET_TYPES)
+		return -EINVAL;
+	else
+		return snet_df[info->syscall](skb_rsp, info);
+}
+
+int snet_nl_size_by_syscall(struct snet_info *info)
+{
+	unsigned int size_addr4_port = nla_total_size(sizeof(struct in_addr)) +
+				       nla_total_size(sizeof(u16));
+	unsigned int size_addr6_port = nla_total_size(sizeof(struct in6_addr)) +
+				       nla_total_size(sizeof(u16));
+
+	unsigned int sbs4[] = {
+		[SNET_SOCKET_CREATE]		= nla_total_size(sizeof(u8)),
+		[SNET_SOCKET_BIND]		= size_addr4_port,
+		[SNET_SOCKET_CONNECT]		= 2 * size_addr4_port,
+		[SNET_SOCKET_LISTEN]		= size_addr4_port,
+		[SNET_SOCKET_ACCEPT]		= size_addr4_port,
+		[SNET_SOCKET_POST_ACCEPT]	= 2 * size_addr4_port,
+		[SNET_SOCKET_SENDMSG]		= 2 * size_addr4_port +
+						  info->len +
+						  nla_total_size(sizeof(u32)),
+		[SNET_SOCKET_RECVMSG]		= 2 * size_addr4_port,
+		[SNET_SOCKET_SOCK_RCV_SKB]	= 2 * size_addr4_port,
+		[SNET_SOCKET_CLOSE]		= 2 * size_addr4_port,
+	};
+
+	unsigned int sbs6[] = {
+		[SNET_SOCKET_CREATE]		= nla_total_size(sizeof(u8)),
+		[SNET_SOCKET_BIND]		= size_addr6_port,
+		[SNET_SOCKET_CONNECT]		= 2 * size_addr6_port,
+		[SNET_SOCKET_LISTEN]		= size_addr6_port,
+		[SNET_SOCKET_ACCEPT]		= size_addr6_port,
+		[SNET_SOCKET_POST_ACCEPT]	= 2 * size_addr6_port,
+		[SNET_SOCKET_SENDMSG]		= 2 * size_addr6_port +
+						  info->len +
+						  nla_total_size(sizeof(u32)),
+		[SNET_SOCKET_RECVMSG]		= 2 * size_addr6_port,
+		[SNET_SOCKET_SOCK_RCV_SKB]	= 2 * size_addr6_port,
+		[SNET_SOCKET_CLOSE]		= 2 * size_addr6_port,
+	};
+
+	if (info->syscall >= SNET_NR_SOCKET_TYPES)
+		return -EINVAL;
+	else {
+		switch (info->family) {
+		case AF_INET:
+			return sbs4[info->syscall];
+			break;
+		case AF_INET6:
+			return sbs6[info->syscall];
+			break;
+		default:
+			return -EINVAL;
+			break;
+		}
+	}
+}
diff --git a/security/snet/snet_netlink_helper.h b/security/snet/snet_netlink_helper.h
new file mode 100644
index 0000000..d12e563
--- /dev/null
+++ b/security/snet/snet_netlink_helper.h
@@ -0,0 +1,7 @@
+#ifndef _SNET_NETLINK_HELPER_H
+#define _SNET_NETLINK_HELPER_H
+
+int snet_nl_fill_by_syscall(struct sk_buff *skb_rsp, struct snet_info *info);
+int snet_nl_size_by_syscall(struct snet_info *info);
+
+#endif /* SNET_NETLINK_HELPER_H */
-- 
1.6.3.3

^ permalink raw reply related

* [RFC v2 08/10] snet: introduce snet_verdict
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

This patch adds the snet's subsystem responsive of managing verdicts

snet is using the word 'verdict' for the returning value of LSM hooks.
Different states exist (grant/deny/pending/none).

This patch introduces a hashtable 'verdict_hash' and operations (set/get/search..)
in order to manage verdicts. Syscalls are waiting, inside a classical waitqueue,
for theirs verdicts or for a timeout. Timeout value and the default verdict
policy are configurable at boot or by the snet_netlink subsystem.
With the help of the communication's subsystem, verdicts are coming from userspace

Signed-off-by: Samir Bellabes <sam@synack.fr>
---
 security/snet/snet_verdict.c |  184 ++++++++++++++++++++++++++++++++++++++++++
 security/snet/snet_verdict.h |   23 +++++
 2 files changed, 207 insertions(+), 0 deletions(-)
 create mode 100644 security/snet/snet_verdict.c
 create mode 100644 security/snet/snet_verdict.h

diff --git a/security/snet/snet_verdict.c b/security/snet/snet_verdict.c
new file mode 100644
index 0000000..480a7f8
--- /dev/null
+++ b/security/snet/snet_verdict.c
@@ -0,0 +1,184 @@
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+#include <linux/snet.h>
+#include "snet_verdict.h"
+
+static struct list_head *snet_vdh;
+static rwlock_t snet_vdh_lock = __RW_LOCK_UNLOCKED();
+
+struct snet_verdict_entry {
+	struct list_head list;
+	u32 verdict_id;
+	enum snet_verdict verdict;
+};
+
+static atomic_t value = ATOMIC_INIT(1);
+
+/* when waiting for a verdict, process is added to this queue */
+static DECLARE_WAIT_QUEUE_HEAD(snet_wq);
+
+/* lookup for a verdict - before using this function, lock snet_vdh_lock */
+static struct snet_verdict_entry *__snet_verdict_lookup(const u32 verdict_id)
+{
+	unsigned int h = 0;
+	struct list_head *l = NULL;
+	struct snet_verdict_entry *s = NULL;
+
+	h = verdict_id % snet_vdh_size;
+	l = &snet_vdh[h];
+
+	list_for_each_entry(s, l, list) {
+		if (s->verdict_id == verdict_id) {
+			return s;
+		}
+	}
+	return NULL;
+}
+
+const enum snet_verdict snet_verdict_wait(const u32 verdict_id)
+{
+	enum snet_verdict verdict = SNET_VERDICT_NONE;
+	long ret = 0;
+
+	ret = wait_event_timeout(snet_wq,
+				 (verdict = snet_verdict_get(verdict_id))
+				 != SNET_VERDICT_PENDING,
+				 snet_verdict_delay * HZ);
+	if (ret)
+		return snet_verdict_get(verdict_id);
+	else
+		return SNET_VERDICT_NONE;
+}
+
+const enum snet_verdict snet_verdict_get(const u32 verdict_id)
+{
+	enum snet_verdict v = SNET_VERDICT_NONE;
+	struct snet_verdict_entry *data = NULL;
+
+	read_lock_bh(&snet_vdh_lock);
+	data = __snet_verdict_lookup(verdict_id);
+	if (data != NULL)
+		v = data->verdict;
+
+	read_unlock_bh(&snet_vdh_lock);
+	return v;
+}
+
+int snet_verdict_set(const u32 verdict_id, const enum snet_verdict verdict)
+{
+	struct snet_verdict_entry *data = NULL;
+	int ret = -EINVAL;
+
+	if (verdict >= SNET_NR_VERDICT_TYPES)
+		goto out;
+
+	write_lock_bh(&snet_vdh_lock);
+	data = __snet_verdict_lookup(verdict_id);
+	if (data != NULL) {
+		/* if verdict is already set because of
+		   timeout, we won't modify it */
+		if (data->verdict == SNET_VERDICT_PENDING) {
+			data->verdict = verdict;
+			ret = 0;
+		}
+	}
+	write_unlock_bh(&snet_vdh_lock);
+	wake_up(&snet_wq);
+out:
+	return ret;
+}
+
+int snet_verdict_remove(const u32 verdict_id)
+{
+	struct snet_verdict_entry *data = NULL;
+
+	write_lock_bh(&snet_vdh_lock);
+	data = __snet_verdict_lookup(verdict_id);
+	if (data == NULL) {
+		write_unlock_bh(&snet_vdh_lock);
+		return -EINVAL;
+	}
+	pr_debug("(verdict_id=%u)\n", data->verdict_id);
+	list_del(&data->list);
+	write_unlock_bh(&snet_vdh_lock);
+	kfree(data);
+	return 0;
+}
+
+int snet_verdict_insert(void)
+{
+	struct snet_verdict_entry *data = NULL;
+	unsigned int h = 0;
+	u32 verdict_id = 0;
+
+	data = kzalloc(sizeof(struct snet_verdict_entry), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	do {
+		verdict_id = atomic_inc_return(&value);
+	} while (verdict_id == 0);
+
+	data->verdict_id = verdict_id;
+	data->verdict = SNET_VERDICT_PENDING;
+	INIT_LIST_HEAD(&(data->list));
+	h = data->verdict_id % snet_vdh_size;
+
+	write_lock_bh(&snet_vdh_lock);
+	list_add_tail(&data->list, &snet_vdh[h]);
+	pr_debug("[%u]=(verdict_id=%u)\n", h, data->verdict_id);
+	write_unlock_bh(&snet_vdh_lock);
+
+	return verdict_id;
+}
+
+void snet_verdict_flush(void)
+{
+	unsigned int i = 0;
+
+	write_lock_bh(&snet_vdh_lock);
+	for (i = 0; i < snet_vdh_size; i++) {
+		struct snet_verdict_entry *data, *tmp;
+		list_for_each_entry_safe(data, tmp, &snet_vdh[i], list) {
+			list_del(&data->list);
+			kfree(data);
+		}
+	}
+	write_unlock_bh(&snet_vdh_lock);
+	return;
+}
+
+/* init function */
+int snet_verdict_init(void)
+{
+	int err = 0, i = 0;
+
+	snet_vdh = kzalloc(sizeof(struct list_head) * snet_vdh_size,
+			  GFP_KERNEL);
+	if (!snet_vdh) {
+		printk(KERN_WARNING
+		       "snet: can't alloc memory for verdict\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < snet_vdh_size; i++)
+		INIT_LIST_HEAD(&snet_vdh[i]);
+
+out:
+	return err;
+}
+
+/* exit function */
+void snet_verdict_exit(void)
+{
+	if (snet_vdh) {
+		kfree(snet_vdh);
+		snet_vdh = NULL;
+	}
+
+	return;
+}
diff --git a/security/snet/snet_verdict.h b/security/snet/snet_verdict.h
new file mode 100644
index 0000000..07e8638
--- /dev/null
+++ b/security/snet/snet_verdict.h
@@ -0,0 +1,23 @@
+#ifndef _SNET_VERDICT_H
+#define _SNET_VERDICT_H
+
+extern unsigned int snet_vdh_size;
+extern unsigned int snet_verdict_delay;
+
+/* helper functions */
+const enum snet_verdict snet_verdict_wait(const u32 verdict_id);
+
+/* manipulate the verdicts hash table */
+const enum snet_verdict snet_verdict_get(const u32 verdict_id);
+int snet_verdict_set(const u32 verdict_id, const enum snet_verdict verdict);
+int snet_verdict_insert(void);
+int snet_verdict_remove(const u32 verdict_id);
+int snet_verdict_insert(void);
+void snet_verdict_flush(void);
+
+/* init function */
+int snet_verdict_init(void);
+/* exit function */
+void snet_verdict_exit(void);
+
+#endif /* _SNET_VERDICT_H */
-- 
1.6.3.3


^ permalink raw reply related

* [RFC v2 09/10] snet: introduce snet_ticket
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

this patch adds the snet's subsystem managing granted-access tickets

snet is using the term 'ticket' for refering to a structure which keeps
informations about verdict, coming from userspace.

generic informations:
  timeout
  syscall
  protocol
  verdict

protocol-dependant informations : (so some infos may not be used)
  address family
  socket type
  source address
  source port
  distant address
  distant port

ticket are attached to the "void *security" pointer of task_struct

there are 3 modes:

0. no ticket - SNET_TICKET_OFF
   every syscalls has to be verified by userspace.

1. timeout fixed - SNET_TICKET_FIX
   for each response from the userspace, we are creating a ticket,
   attached to the task_struct, with the filled informations, and a
   fixed timeout value (10 secs by default).
   then before asking userspace, kernel mecanism is checking existing
   tickets for the task_struct, if there is a granted-access ticket, we
   are using the verdict value attached.
   after the timeout value, the ticket is destroyed.

2. timeout with extendable value - SNET_TICKET_EXTEND
   this is the same mecanism as 1, but every time a ticket is matched
   and used, the timeout value is reset to the default value, so its
   life is extended.

Signed-off-by: Samir Bellabes <sam@synack.fr>
---
 security/snet/snet_ticket.c        |  171 ++++++++++++++++++++++++++++++++++++
 security/snet/snet_ticket.h        |   37 ++++++++
 security/snet/snet_ticket_helper.c |  127 ++++++++++++++++++++++++++
 security/snet/snet_ticket_helper.h |    8 ++
 4 files changed, 343 insertions(+), 0 deletions(-)
 create mode 100644 security/snet/snet_ticket.c
 create mode 100644 security/snet/snet_ticket.h
 create mode 100644 security/snet/snet_ticket_helper.c
 create mode 100644 security/snet/snet_ticket_helper.h

diff --git a/security/snet/snet_ticket.c b/security/snet/snet_ticket.c
new file mode 100644
index 0000000..62ced7b
--- /dev/null
+++ b/security/snet/snet_ticket.c
@@ -0,0 +1,171 @@
+#include <linux/slab.h>
+#include <linux/cred.h>
+#include <linux/jhash.h>
+#include <linux/security.h>
+#include <linux/snet.h>
+#include "snet_ticket.h"
+#include "snet_ticket_helper.h"
+
+#define HSIZE 16
+
+enum snet_verdict snet_ticket_check(struct snet_info *info)
+{
+	struct snet_ticket *st = NULL;
+	unsigned int h = 0, verdict = SNET_VERDICT_NONE;
+	struct list_head *l = NULL;
+	struct snet_task_security *tsec = NULL;
+
+	if (snet_ticket_mode == SNET_TICKET_OFF)
+		goto out;
+
+	tsec = (struct snet_task_security*) current_security();
+
+	h = jhash_2words(info->syscall, info->protocol, 0) % HSIZE;
+	l = &tsec->hash[h];
+
+	read_lock_bh(&tsec->lock);
+	list_for_each_entry(st, l, list) {
+		if (__ticket_check(st, info)) {
+			verdict = st->verdict;
+			pr_debug("snet_ticket found: ticket=%p tsec=%p\n",
+				 st, st->tsec);
+			if (snet_ticket_mode == SNET_TICKET_EXTEND) {
+				mod_timer(&st->timeout,
+					  jiffies + snet_ticket_delay * HZ);
+			}
+			break;
+		}
+	}
+	read_unlock_bh(&tsec->lock);
+out:
+	return verdict;
+}
+
+static void snet_ticket_timeout(unsigned long arg)
+{
+	struct snet_ticket *st = (struct snet_ticket*)arg;
+
+	pr_debug("snet_ticket_timeout: ticket=%p tsec=%p\n", st, st->tsec);
+
+	write_lock_bh(&st->tsec->lock);
+	list_del(&st->list);
+	write_unlock_bh(&st->tsec->lock);
+	kfree(st);
+	return;
+}
+
+static struct snet_ticket *snet_ticket_alloc(void)
+{
+	struct snet_ticket *st = NULL;
+
+	st = kzalloc(sizeof(struct snet_ticket), GFP_KERNEL);
+	if (st == NULL)
+		goto out;
+
+	INIT_LIST_HEAD(&st->list);
+	init_timer(&st->timeout);
+	st->timeout.expires = snet_ticket_delay * HZ;
+out:
+	return st;
+}
+
+static void snet_ticket_insert(struct snet_ticket *st)
+{
+	unsigned int h;
+	struct list_head *l;
+
+	h = jhash_2words(st->syscall, st->protocol, 0) % HSIZE;
+	l = &(st->tsec->hash[h]);
+
+	st->timeout.expires += jiffies;
+	add_timer(&st->timeout);
+
+	write_lock_bh(&(st->tsec->lock));
+	list_add_tail(&st->list, l);
+	write_unlock_bh(&(st->tsec->lock));
+	return;
+}
+
+void snet_ticket_create(struct snet_info *info, enum snet_verdict verdict)
+{
+	struct snet_ticket *st;
+	struct snet_task_security *tsec = NULL;
+
+	if (snet_ticket_mode == SNET_TICKET_OFF)
+		goto out;
+
+	tsec = (struct snet_task_security*) current_security();
+
+	st = snet_ticket_alloc();
+	if (st == NULL)
+		goto out;
+
+	st->tsec = tsec;
+	snet_ticket_fill(st, info, verdict);
+	setup_timer(&st->timeout, snet_ticket_timeout, (unsigned long)st);
+	snet_ticket_insert(st);
+out:
+	return;
+}
+
+int snet_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
+{
+	unsigned int index = 0;
+	struct snet_task_security *tsec = NULL;
+
+	tsec = kzalloc(sizeof(struct snet_task_security), gfp);
+	if (tsec == NULL)
+		return -ENOMEM;
+
+	pr_debug("ticket_prepare_creds: pid=%u tsec=%p\n", current->pid, tsec);
+	rwlock_init(&tsec->lock);
+	for (index = 0; index < HSIZE; index++)
+		INIT_LIST_HEAD(&tsec->hash[index]);
+
+	new->security = tsec;
+	return 0;
+}
+
+void snet_cred_free(struct cred *cred)
+{
+	struct snet_task_security *tsec = cred->security;
+	unsigned int index;
+
+	pr_debug("ticket_free_cred: pid=%u tsec=%p\n",  current->pid, tsec);
+
+	write_lock_bh(&tsec->lock);
+	/* destroy all tickets */
+	for (index = 0; index < HSIZE; index++) {
+		struct snet_ticket *st, *tmp;
+		list_for_each_entry_safe(st, tmp, &tsec->hash[index], list) {
+			if (del_timer_sync(&st->timeout)) {
+				pr_debug("ticket_cred_free: [%u] ticket=%p tsec=%p\n",
+					 index, st, st->tsec);
+				list_del(&st->list);
+				kfree(st);
+			}
+		}
+	}
+	cred->security = NULL;
+	write_unlock_bh(&tsec->lock);
+	kfree(tsec);
+	return;
+}
+
+int snet_ticket_init(void)
+{
+	unsigned int index = 0;
+	struct cred *cred = (struct cred *) current->real_cred;
+	struct snet_task_security *tsec = NULL;
+
+	tsec = kzalloc(sizeof(struct snet_task_security), GFP_KERNEL);
+	if (tsec == NULL)
+		return -ENOMEM;
+
+	rwlock_init(&tsec->lock);
+	for (index = 0; index < HSIZE; index++)
+		INIT_LIST_HEAD(&tsec->hash[index]);
+
+	cred->security = tsec;
+	return 0;
+}
diff --git a/security/snet/snet_ticket.h b/security/snet/snet_ticket.h
new file mode 100644
index 0000000..b6d1020
--- /dev/null
+++ b/security/snet/snet_ticket.h
@@ -0,0 +1,37 @@
+#ifndef _SNET_TICKET_H
+#define _SNET_TICKET_H
+
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/cred.h>
+#include <linux/snet.h>
+
+struct snet_task_security {
+	struct list_head hash[16];
+	rwlock_t lock;
+};
+
+struct snet_ticket {
+	struct list_head list;
+	struct snet_task_security *tsec;
+	struct timer_list timeout;
+
+	enum snet_syscall syscall;
+	u8 protocol;
+	u8 family;
+	int type;
+	struct snet_sock_half src;
+	struct snet_sock_half dst;
+	enum snet_verdict verdict;
+};
+
+extern unsigned int snet_ticket_delay;
+extern unsigned int snet_ticket_mode;
+
+void snet_cred_free(struct cred *cred);
+int snet_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
+enum snet_verdict snet_ticket_check(struct snet_info *info);
+void snet_ticket_create(struct snet_info *info, enum snet_verdict verdict);
+int snet_ticket_init(void);
+
+#endif	/* _SNET_TICKET_H */
diff --git a/security/snet/snet_ticket_helper.c b/security/snet/snet_ticket_helper.c
new file mode 100644
index 0000000..2dc9b94
--- /dev/null
+++ b/security/snet/snet_ticket_helper.c
@@ -0,0 +1,127 @@
+#include <linux/sched.h>
+#include <linux/socket.h>
+#include <linux/snet.h>
+#include "snet_ticket.h"
+#include "snet_utils.h"
+
+static int check_create(struct snet_ticket *st, struct snet_info *info)
+{
+	return (st->type == info->type);
+}
+
+static int check_src(struct snet_ticket *st, struct snet_info *info)
+{
+	switch (info->family) {
+	case AF_INET:
+		if ((st->src.u3.ip == info->src.u3.ip) &&
+		    (st->src.u.port == info->src.u.port))
+			return 1;
+		break;
+	case AF_INET6:
+		if ((!memcmp(&st->src.u3.ip6, &info->src.u3.ip6,
+			     sizeof(info->src.u3.ip6))) &&
+		    (st->src.u.port == info->src.u.port))
+			return 1;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int check_dst(struct snet_ticket *st, struct snet_info *info)
+{
+	switch (info->family) {
+	case AF_INET:
+		if ((st->dst.u3.ip == info->dst.u3.ip) &&
+		    (st->dst.u.port == info->dst.u.port))
+			return 1;
+		break;
+	case AF_INET6:
+		if ((!memcmp(&st->dst.u3.ip6, &info->dst.u3.ip6,
+			     sizeof(info->dst.u3.ip6))) &&
+		    (st->dst.u.port == info->dst.u.port))
+			return 1;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int check_src_and_dst(struct snet_ticket *st, struct snet_info *info)
+{
+	return (check_src(st, info) && check_dst(st, info));
+}
+
+static int check_none(struct snet_ticket *st, struct snet_info *info)
+{
+	return 0;
+}
+
+int __ticket_check(struct snet_ticket *st, struct snet_info *info)
+{
+	static int (*ticket_df[])(struct snet_ticket *, struct snet_info *) = {
+		[SNET_SOCKET_CREATE]		= &check_create,
+		[SNET_SOCKET_BIND]		= &check_src,
+		[SNET_SOCKET_CONNECT]		= &check_dst,
+		[SNET_SOCKET_LISTEN]		= &check_src,
+		[SNET_SOCKET_ACCEPT]		= &check_src,
+		[SNET_SOCKET_POST_ACCEPT]	= &check_none,
+		[SNET_SOCKET_SENDMSG]		= &check_src_and_dst,
+		[SNET_SOCKET_RECVMSG]		= &check_src_and_dst,
+		[SNET_SOCKET_SOCK_RCV_SKB]	= &check_src_and_dst,
+		[SNET_SOCKET_CLOSE]		= &check_none,
+	};
+
+	if (info->syscall >= SNET_NR_SOCKET_TYPES)
+		return 0;
+	else {
+		if ((st->syscall == info->syscall) &&
+		    (st->protocol == info->protocol) &&
+		    (st->family == info->family) &&
+		    ticket_df[info->syscall](st, info))
+			return 1;
+		else
+			return 0;
+	}
+}
+
+void snet_ticket_fill(struct snet_ticket *st, struct snet_info *info,
+		      enum snet_verdict verdict)
+{
+	st->syscall = info->syscall;
+	st->protocol = info->protocol;
+	st->family = info->family;
+	st->src.u.port = info->src.u.port;
+	st->dst.u.port = info->dst.u.port;
+	st->verdict = verdict;
+
+	switch (info->family) {
+	case AF_INET:
+		st->src.u3.ip = info->src.u3.ip;
+		st->dst.u3.ip = info->dst.u3.ip;
+		pr_debug("ticket=%p [syscall=%s protocol=%u "
+			 "family=%u %pI4:%u->%pI4:%u] verdict=%s | tsec=%p pid=%u\n",
+			 st, snet_syscall_name(st->syscall), st->protocol,
+			 st->family, &st->src.u3.ip, st->src.u.port,
+			 &st->dst.u3.ip, st->dst.u.port,
+			 snet_verdict_name(st->verdict), st->tsec, current->pid);
+		break;
+	case AF_INET6:
+		memcpy(&st->src.u3.ip6, &info->src.u3.ip6,
+		       sizeof(info->src.u3.ip6));
+		memcpy(&st->dst.u3.ip6, &info->dst.u3.ip6,
+		       sizeof(info->dst.u3.ip6));
+		pr_debug("ticket=%p [syscall=%s protocol=%u "
+			 "family=%u %pI6:%u->%pI6:%u] verdict=%s | tsec=%p pid=%u\n",
+			 st, snet_syscall_name(st->syscall), st->protocol,
+			 st->family, &st->src.u3.ip6, st->src.u.port,
+			 &st->dst.u3.ip6, st->dst.u.port,
+			 snet_verdict_name(st->verdict), st->tsec, current->pid);
+		break;
+	default:
+		break;
+	}
+	return;
+}
diff --git a/security/snet/snet_ticket_helper.h b/security/snet/snet_ticket_helper.h
new file mode 100644
index 0000000..177bca5
--- /dev/null
+++ b/security/snet/snet_ticket_helper.h
@@ -0,0 +1,8 @@
+#ifndef _SNET_TICKET_HELPER_H
+#define _SNET_TICKET_HELPER_H
+
+void snet_ticket_fill(struct snet_ticket *st, struct snet_info *info,
+		      enum snet_verdict verdict);
+int __ticket_check(struct snet_ticket *st, struct snet_info *info);
+
+#endif	/* _SNET_TICKET_HELPER_H */
-- 
1.6.3.3

^ permalink raw reply related

* [RFC v2 10/10] snet: introduce snet_utils
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

This patch provides helper functions for other subsystems

Signed-off-by: Samir Bellabes <sam@synack.fr>
---
 security/snet/snet_utils.c |   38 ++++++++++++++++++++++++++++++++++++++
 security/snet/snet_utils.h |   10 ++++++++++
 2 files changed, 48 insertions(+), 0 deletions(-)
 create mode 100644 security/snet/snet_utils.c
 create mode 100644 security/snet/snet_utils.h

diff --git a/security/snet/snet_utils.c b/security/snet/snet_utils.c
new file mode 100644
index 0000000..e9178d7
--- /dev/null
+++ b/security/snet/snet_utils.c
@@ -0,0 +1,38 @@
+#include <linux/types.h>
+#include <linux/snet.h>
+
+const char *snet_verdict_name(const enum snet_verdict cmd)
+{
+	static const char *const verdict_name[] = {
+		[SNET_VERDICT_GRANT]	= "Grant",
+		[SNET_VERDICT_DENY]	= "Deny",
+		[SNET_VERDICT_PENDING]	= "Pending",
+		[SNET_VERDICT_NONE]	= "None",
+	};
+
+	if (cmd >= SNET_NR_VERDICT_TYPES)
+		return "INVALID";
+	else
+		return verdict_name[cmd];
+}
+
+const char *snet_syscall_name(const enum snet_syscall sys)
+{
+	static const char *const syscall_name[] = {
+		[SNET_SOCKET_CREATE]		= "Create",
+		[SNET_SOCKET_BIND]		= "Bind",
+		[SNET_SOCKET_CONNECT]		= "Connect",
+		[SNET_SOCKET_LISTEN]		= "Listen",
+		[SNET_SOCKET_ACCEPT]		= "Accept",
+		[SNET_SOCKET_POST_ACCEPT]	= "Post Accept",
+		[SNET_SOCKET_SENDMSG]		= "Sendmsg",
+		[SNET_SOCKET_RECVMSG]		= "Recvmsg",
+		[SNET_SOCKET_SOCK_RCV_SKB]	= "Sock Rcv Skb",
+		[SNET_SOCKET_CLOSE]		= "Close",
+	};
+
+	if (sys >= SNET_NR_SOCKET_TYPES)
+		return "INVALID";
+	else
+		return syscall_name[sys];
+}
diff --git a/security/snet/snet_utils.h b/security/snet/snet_utils.h
new file mode 100644
index 0000000..4dad18b
--- /dev/null
+++ b/security/snet/snet_utils.h
@@ -0,0 +1,10 @@
+#ifndef _SNET_UTILS_H
+#define _SNET_UTILS_H
+
+#include <linux/skbuff.h>
+
+int snet_data_fill(struct sk_buff *skb_rsp, struct snet_info *info);
+const char *snet_verdict_name(const enum snet_verdict cmd);
+const char *snet_syscall_name(const enum snet_syscall sys);
+
+#endif	/* _SNET_UTILS_H */
-- 
1.6.3.3


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox