All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] RFC, aiding pid/network correlation
@ 2014-08-01  1:21 Peter Moody
  2014-08-01  1:21 ` [PATCH 1/2] security: create task_post_create callback Peter Moody
                   ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Peter Moody @ 2014-08-01  1:21 UTC (permalink / raw)
  To: linux-security-module; +Cc: brandon.carpenter, casey, netdev, Peter Moody

I'm interested in having a host-based monitoring mechanism in
place in the linux kernel. At this point I'm specifically looking
to tie any given packet seen on the network back to the process
that sent or received it. This is the sort of information our
incident responders are constantly asking for.

This is round 2 of the patchset. It's essentially taking HONE [1],
a kernel module originally written by Brandon Carpenter and switches
the hooks to use the standard (plus a new one, task_post_create) LSM
hooks + a run through cleanfile/checkpatch.

At a high level, Hone hooks process/socket creations/terminations
and inet/inet6 packets that are sent or received. A userspace
application can then correlate packet to process by reading the
events from the kernel.

(Note, there doesn't appear to be outbound version of the callback
socket_sock_rcv_skb and the socket_sendmsg/socket_recvmsg
are called too early in the process to be used so this uses netfilter
hooks.)

This patchset makes the events available as text via securityfs
in /sys/kernel/security/hone/text and /sys/kernel/security/hone/pcapng.
The text output looks like

3.350826817 EXEC 718 1 0 0 "/usr/sbin/cupsd" /usr/sbin/cupsd -f
3.350826817 SOCK O 718 1 0 0 b14e0000
...
5301.871561546 EXEC 2652 2586 1000 1000 "/bin/less" less
5303.104510870 EXEC 2653 2651 0 0 "/bin/cat" cat /sys/kernel/security/hone/text
5303.110322648 PAKT O 382d0700 2524 TCPv4 169.254.0.11:22 -> 169.254.0.2:49387 120

and the pcapng format is described in hone_pcapng.h.

There are some drawbacks with this method. Notably, it doesn't
accurately track the owning pid of sockets passed via dup(), dup2()
etc.

This particular approach is all very experimental. We had a need
for this level of monitoring on some of our machines (did I mention
the incident responders?) and HONE had the best features/efficiency.

I've CC'd the netdev folks at James' suggestion. I CC'd you, Casey
as you were the one who suggested this be a proper LSM.

So I'm humbly requesting comments.

 * Is there a better (more efficient/extensible) way to do this?
 * Is there already an existing mechanism to do this?
 * Is there any interest in something like this living in the
   kernel? Or is the dkms distributed path the way to go?

And if this is all reasonable, is it possible to add a
socket_sock_send_skb callback and where might that go?

Finally, the linux-sensor project was released under the GPL but
I'm not sure if there are any copyright issues ... ? I've just
kept the copyright comments in any event.

This has been tested against security-next

[1] https://github.com/HoneProject/Linux-Sensor

Peter Moody (2):
  security: create task_post_create callback.
  security: Hone LSM

 include/linux/hone.h               |  50 +++
 include/linux/security.h           |   8 +
 kernel/fork.c                      |   1 +
 security/Kconfig                   |   1 +
 security/Makefile                  |   2 +
 security/capability.c              |   5 +
 security/hone/Kconfig              |   8 +
 security/hone/Makefile             |   3 +
 security/hone/hone.h               | 164 ++++++++++
 security/hone/hone_event.c         | 625 +++++++++++++++++++++++++++++++++++++
 security/hone/hone_lsm.c           | 183 +++++++++++
 security/hone/hone_mmutil.c        | 106 +++++++
 security/hone/hone_mmutil.h        |  20 ++
 security/hone/hone_notify.c        | 450 ++++++++++++++++++++++++++
 security/hone/hone_pcapng.c        | 596 +++++++++++++++++++++++++++++++++++
 security/hone/hone_pcapng.h        |  30 ++
 security/hone/hone_ringbuf.c       |  51 +++
 security/hone/hone_ringbuf.h       |  34 ++
 security/hone/hone_socket_lookup.c | 264 ++++++++++++++++
 security/security.c                |   5 +
 20 files changed, 2606 insertions(+)
 create mode 100644 include/linux/hone.h
 create mode 100644 security/hone/Kconfig
 create mode 100644 security/hone/Makefile
 create mode 100644 security/hone/hone.h
 create mode 100644 security/hone/hone_event.c
 create mode 100644 security/hone/hone_lsm.c
 create mode 100644 security/hone/hone_mmutil.c
 create mode 100644 security/hone/hone_mmutil.h
 create mode 100644 security/hone/hone_notify.c
 create mode 100644 security/hone/hone_pcapng.c
 create mode 100644 security/hone/hone_pcapng.h
 create mode 100644 security/hone/hone_ringbuf.c
 create mode 100644 security/hone/hone_ringbuf.h
 create mode 100644 security/hone/hone_socket_lookup.c

-- 
2.0.0.526.g5318336


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 1/2] security: create task_post_create callback.
  2014-08-01  1:21 [PATCH v2 0/2] RFC, aiding pid/network correlation Peter Moody
@ 2014-08-01  1:21 ` Peter Moody
  2014-08-01  1:21 ` [PATCH 2/2] security: Hone LSM Peter Moody
  2014-08-01 12:16 ` [PATCH v2 0/2] RFC, aiding pid/network correlation Samir Bellabes
  2 siblings, 0 replies; 19+ messages in thread
From: Peter Moody @ 2014-08-01  1:21 UTC (permalink / raw)
  To: linux-security-module; +Cc: brandon.carpenter, casey, netdev, Peter Moody

The current LSM framework doesn't have a mechanism for accessing
a task after it's been created but before it's been started. This
patch adds a task_post_create callback so an LSM can access a newly
created task before it has actually started running.

Signed-off-by: Peter Moody <pmoody@google.com>
---
 include/linux/security.h | 8 ++++++++
 kernel/fork.c            | 1 +
 security/capability.c    | 5 +++++
 security/security.c      | 5 +++++
 4 files changed, 19 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index 623f90e..58abf3b 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -668,6 +668,9 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	manual page for definitions of the @clone_flags.
  *	@clone_flags contains the flags indicating what should be shared.
  *	Return 0 if permission is granted.
+ * @task_post_create:
+ *	This hook allows a module to update or allocate a per-task security
+ *	structure.
  * @task_free:
  *	@task task being freed
  *	Handle release of task-related resources. (Note that this can be called
@@ -1566,6 +1569,7 @@ struct security_operations {
 	int (*file_open) (struct file *file, const struct cred *cred);
 
 	int (*task_create) (unsigned long clone_flags);
+	void (*task_post_create)(struct task_struct *task);
 	void (*task_free) (struct task_struct *task);
 	int (*cred_alloc_blank) (struct cred *cred, gfp_t gfp);
 	void (*cred_free) (struct cred *cred);
@@ -1840,6 +1844,7 @@ int security_file_send_sigiotask(struct task_struct *tsk,
 int security_file_receive(struct file *file);
 int security_file_open(struct file *file, const struct cred *cred);
 int security_task_create(unsigned long clone_flags);
+void security_task_post_create(struct task_struct *task);
 void security_task_free(struct task_struct *task);
 int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
 void security_cred_free(struct cred *cred);
@@ -2340,6 +2345,9 @@ static inline int security_task_create(unsigned long clone_flags)
 	return 0;
 }
 
+static inline void security_task_post_create(struct task_struct *task)
+{ }
+
 static inline void security_task_free(struct task_struct *task)
 { }
 
diff --git a/kernel/fork.c b/kernel/fork.c
index ed4bc33..d6cca1c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1657,6 +1657,7 @@ long do_fork(unsigned long clone_flags,
 		struct completion vfork;
 		struct pid *pid;
 
+		security_task_post_create(p);
 		trace_sched_process_fork(current, p);
 
 		pid = get_task_pid(p, PIDTYPE_PID);
diff --git a/security/capability.c b/security/capability.c
index a74fde6..14d882f 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -369,6 +369,10 @@ static int cap_task_create(unsigned long clone_flags)
 	return 0;
 }
 
+static void cap_task_post_create(struct task_struct *task)
+{
+}
+
 static void cap_task_free(struct task_struct *task)
 {
 }
@@ -1013,6 +1017,7 @@ void __init security_fixup_ops(struct security_operations *ops)
 	set_to_cap_if_null(ops, file_receive);
 	set_to_cap_if_null(ops, file_open);
 	set_to_cap_if_null(ops, task_create);
+	set_to_cap_if_null(ops, task_post_create);
 	set_to_cap_if_null(ops, task_free);
 	set_to_cap_if_null(ops, cred_alloc_blank);
 	set_to_cap_if_null(ops, cred_free);
diff --git a/security/security.c b/security/security.c
index e41b1a8..42a7ec8 100644
--- a/security/security.c
+++ b/security/security.c
@@ -807,6 +807,11 @@ int security_task_create(unsigned long clone_flags)
 	return security_ops->task_create(clone_flags);
 }
 
+void security_task_post_create(struct task_struct *task)
+{
+	security_ops->task_post_create(task);
+}
+
 void security_task_free(struct task_struct *task)
 {
 #ifdef CONFIG_SECURITY_YAMA_STACKED
-- 
2.0.0.526.g5318336


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 2/2] security: Hone LSM
  2014-08-01  1:21 [PATCH v2 0/2] RFC, aiding pid/network correlation Peter Moody
  2014-08-01  1:21 ` [PATCH 1/2] security: create task_post_create callback Peter Moody
@ 2014-08-01  1:21 ` Peter Moody
  2014-08-01 12:16 ` [PATCH v2 0/2] RFC, aiding pid/network correlation Samir Bellabes
  2 siblings, 0 replies; 19+ messages in thread
From: Peter Moody @ 2014-08-01  1:21 UTC (permalink / raw)
  To: linux-security-module; +Cc: brandon.carpenter, casey, netdev, Peter Moody

This adds the Hone (Host/Network) process <-> packet correlation
module to the linux security subsystem. Hone aims to provide network
administrators with the ability to correlate network activity seen on
the network to the process which sent/received it.

Signed-off-by: Peter Moody <pmoody@google.com>
---
 include/linux/hone.h               |  50 +++
 security/Kconfig                   |   1 +
 security/Makefile                  |   2 +
 security/hone/Kconfig              |   8 +
 security/hone/Makefile             |   3 +
 security/hone/hone.h               | 164 ++++++++++
 security/hone/hone_event.c         | 625 +++++++++++++++++++++++++++++++++++++
 security/hone/hone_lsm.c           | 183 +++++++++++
 security/hone/hone_mmutil.c        | 106 +++++++
 security/hone/hone_mmutil.h        |  20 ++
 security/hone/hone_notify.c        | 450 ++++++++++++++++++++++++++
 security/hone/hone_pcapng.c        | 596 +++++++++++++++++++++++++++++++++++
 security/hone/hone_pcapng.h        |  30 ++
 security/hone/hone_ringbuf.c       |  51 +++
 security/hone/hone_ringbuf.h       |  34 ++
 security/hone/hone_socket_lookup.c | 264 ++++++++++++++++
 16 files changed, 2587 insertions(+)
 create mode 100644 include/linux/hone.h
 create mode 100644 security/hone/Kconfig
 create mode 100644 security/hone/Makefile
 create mode 100644 security/hone/hone.h
 create mode 100644 security/hone/hone_event.c
 create mode 100644 security/hone/hone_lsm.c
 create mode 100644 security/hone/hone_mmutil.c
 create mode 100644 security/hone/hone_mmutil.h
 create mode 100644 security/hone/hone_notify.c
 create mode 100644 security/hone/hone_pcapng.c
 create mode 100644 security/hone/hone_pcapng.h
 create mode 100644 security/hone/hone_ringbuf.c
 create mode 100644 security/hone/hone_ringbuf.h
 create mode 100644 security/hone/hone_socket_lookup.c

diff --git a/include/linux/hone.h b/include/linux/hone.h
new file mode 100644
index 0000000..7ad7ad8
--- /dev/null
+++ b/include/linux/hone.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ */
+
+#include <linux/skbuff.h>
+
+#ifndef _INCLUDE_LINUX_HONE_H
+#define _INCLUDE_LINUX_HONE_H
+
+#define PKTNOT_PACKET_IN 1
+#define PKTNOT_PACKET_OUT 2
+
+/* hone block types for pcapng blocks */
+#define HONE_IF_DESC_BLOCK	0x00000001
+#define HONE_IF_STATS_BLOCK	0x00000005
+#define HONE_PACKET_BLOCK	0x00000006
+#define HONE_PROCESS_BLOCK	0x00000101
+#define HONE_CONNECTION_BLOCK	0x00000102
+#define HONE_SECTION_HDR_BLOCK	0x0A0D0D0A
+
+/* ioctls for controlling hone. */
+#define HEIO_RESTART _IO(0xE0, 0x01)
+#define HEIO_GET_AT_HEAD _IO(0xE0, 0x03)
+#define HEIO_GET_SNAPLEN _IOR(0xE0, 0x04, int)
+#define HEIO_SET_SNAPLEN _IOW(0xE0, 0x05, int)
+#define HEIO_SET_FILTER_SOCK _IOW(0xE0, 0x06, int)
+
+#define HONE_PROCESS 1
+#define HONE_SOCKET 2
+#define HONE_PACKET 3
+#define HONE_USER 0x8000
+
+#define PROC_FORK 1
+#define PROC_EXEC 2
+#define PROC_EXIT 3
+#define PROC_KTHD 4
+
+void hone_exec_handler(int);
+void hone_exit_handler(void);
+void hone_fork_handler(struct task_struct *);
+void hone_raw_rcv_handler(struct sock *, struct sk_buff *);
+void hone_inet_create_handler(int, struct sock *);
+
+#endif
diff --git a/security/Kconfig b/security/Kconfig
index beb86b5..84d2b45 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -122,6 +122,7 @@ source security/smack/Kconfig
 source security/tomoyo/Kconfig
 source security/apparmor/Kconfig
 source security/yama/Kconfig
+source security/hone/Kconfig
 
 source security/integrity/Kconfig
 
diff --git a/security/Makefile b/security/Makefile
index 05f1c93..ff20918 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -8,6 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK)		+= smack
 subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
 subdir-$(CONFIG_SECURITY_YAMA)		+= yama
+subdir-$(CONFIG_SECURITY_HONE)		+= hone
 
 # always enable default capabilities
 obj-y					+= commoncap.o
@@ -22,6 +23,7 @@ obj-$(CONFIG_AUDIT)			+= lsm_audit.o
 obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/
 obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
 obj-$(CONFIG_SECURITY_YAMA)		+= yama/
+obj-$(CONFIG_SECURITY_HONE) 		+= hone/
 obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
 
 # Object integrity file lists
diff --git a/security/hone/Kconfig b/security/hone/Kconfig
new file mode 100644
index 0000000..bdaad6b
--- /dev/null
+++ b/security/hone/Kconfig
@@ -0,0 +1,8 @@
+config SECURITY_HONE
+       bool "HOst NEt corrleation engine support"
+       default n
+       help
+         This selects hone, a tool for correlating packets to
+         processes.
+
+         If you are unsure how to answer this question, answer N.
diff --git a/security/hone/Makefile b/security/hone/Makefile
new file mode 100644
index 0000000..b87c0a8
--- /dev/null
+++ b/security/hone/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SECURITY_HONE)	:= hone.o
+hone-y := hone_lsm.o hone_notify.o hone_ringbuf.o hone_event.o \
+					hone_mmutil.o hone_pcapng.o hone_ringbuf.o hone_socket_lookup.o
diff --git a/security/hone/hone.h b/security/hone/hone.h
new file mode 100644
index 0000000..1533cf7
--- /dev/null
+++ b/security/hone/hone.h
@@ -0,0 +1,164 @@
+#ifndef _SECURITY_HONE_HONE_H
+#define _SECURITY_HONE_HONE_H
+
+#include <linux/hone.h>
+#include <linux/tcp.h>
+
+#define HONE_USER_HEAD (HONE_USER | 1)
+#define HONE_USER_TAIL (HONE_USER | 2)
+
+#define READER_HEAD 0x00000001
+#define READER_INIT 0x00000002
+#define READER_TAIL 0x00000004
+#define READER_FINISH 0x00000008
+#define READER_RESTART 0x0000000F
+#define READER_FILTER_PID 0x00000100
+
+struct guid_struct {
+	uint32_t data1;
+	uint16_t data2;
+	uint16_t data3;
+	uint8_t  data4[8];
+};
+
+struct device_info {
+	struct guid_struct host_guid;
+	bool host_guid_is_set;
+	const char *host_id;
+	const char *comment;
+	struct dentry *dir;
+	struct dentry *pcapng;
+	struct dentry *text;
+};
+
+struct statistics {
+	atomic64_t process;
+	atomic64_t socket;
+	atomic64_t packet;
+};
+
+struct reader_info {
+	unsigned int snaplen;
+	struct timespec boot_time;
+	struct timespec start_time;
+	struct statistics delivered;
+	struct statistics dropped;
+	atomic64_t filtered;
+};
+
+struct process_event {
+	union {
+		struct mm_struct *mm;
+		char *comm;
+	};
+	int event;
+	pid_t pid;
+	pid_t ppid;
+	pid_t tgid;
+	uid_t uid;
+	uid_t euid;
+	uid_t loginuid;
+	gid_t gid;
+	int retval;
+};
+
+struct socket_event {
+	unsigned long sock;
+	int event;
+	pid_t pid;
+	pid_t ppid;
+	pid_t tgid;
+	uid_t uid;
+	gid_t gid;
+};
+
+struct packet_event {
+	unsigned long sock;
+	int dir;
+	int len;
+	pid_t pid;
+	struct sock *sk;
+	struct sk_buff *skb;
+};
+
+struct user_event {
+	void *data;
+};
+
+struct hone_event {
+	int type;
+	union {
+		atomic_t users;
+		struct hone_event *next;
+	};
+	struct timespec ts;
+	union {
+		struct process_event process;
+		struct socket_event socket;
+		struct packet_event packet;
+		struct user_event user;
+	};
+};
+
+struct packet_args {
+	struct sock *sk;
+	struct sk_buff *skb;
+};
+
+#define STATISTICS_INIT {ATOMIC64_INIT(0), ATOMIC64_INIT(0), ATOMIC64_INIT(0)}
+#define DEFINE_STATISTICS(name) struct statistics name = STATISTICS_INIT
+
+static inline void init_statistics(struct statistics *stats)
+{
+	atomic64_set(&stats->process, 0);
+	atomic64_set(&stats->socket, 0);
+	atomic64_set(&stats->packet, 0);
+}
+
+extern void get_hone_statistics(struct statistics *received,
+				struct statistics *dropped,
+				struct timespec *ts);
+
+void free_hone_event(struct hone_event *event);
+
+int hone_notify_init(void);
+int hone_fs_init(void);
+
+int process_notifier_notify(unsigned long event, struct task_struct *task);
+int sock_notifier_notify(unsigned long event, struct sock *sk);
+int packet_notifier_notify(unsigned long event, struct packet_args *pargs);
+int hone_notifier_register(struct notifier_block *nb);
+int hone_notifier_unregister(struct notifier_block *nb);
+
+struct hone_event *__alloc_socket_event(unsigned long v, int val,
+					struct task_struct *task, gfp_t flags);
+struct hone_event *__alloc_process_event(struct task_struct *task, int type,
+                                         gfp_t flags);
+
+static inline void get_hone_event(struct hone_event *event)
+{
+	BUG_ON(unlikely(!atomic_read(&event->users)));
+	atomic_inc(&event->users);
+}
+
+static inline void put_hone_event(struct hone_event *event)
+{
+	BUG_ON(unlikely(!atomic_read(&event->users)));
+	if (atomic_dec_and_test(&event->users))
+		free_hone_event(event);
+}
+
+static inline void put_sock(struct sock *sk)
+{
+	if (sk->sk_state == TCP_TIME_WAIT)
+		inet_twsk_put(inet_twsk(sk));
+	else
+		sock_put(sk);
+}
+
+struct sock *lookup_v4_sock(const struct sk_buff *skb,
+			const struct net_device *indev);
+struct sock *lookup_v6_sock(const struct sk_buff *skb,
+			const struct net_device *indev);
+
+#endif
diff --git a/security/hone/hone_event.c b/security/hone/hone_event.c
new file mode 100644
index 0000000..b2339bc
--- /dev/null
+++ b/security/hone/hone_event.c
@@ -0,0 +1,625 @@
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/fdtable.h>
+#include <linux/fs.h>
+#include <net/sock.h>
+#include <net/inet_sock.h>
+#include <linux/ipv6.h>
+#include <linux/ip.h>
+
+#include <linux/hone.h>
+
+#include "hone.h"
+#include "hone_mmutil.h"
+#include "hone_pcapng.h"
+#include "hone_ringbuf.h"
+
+static struct device_info devinfo = {
+	.comment = NULL,
+	.host_id = NULL,
+	.host_guid_is_set = false
+};
+
+#ifndef CONFIG_HONE_DEFAULT_PAGEORDER
+	#ifdef CONFIG_64BIT
+		#define CONFIG_HONE_DEFAULT_PAGEORDER 3
+	#else
+		#define CONFIG_HONE_DEFAULT_PAGEORDER 2
+	#endif
+#endif
+
+static unsigned int pageorder = CONFIG_HONE_DEFAULT_PAGEORDER;
+#define size_of_pages(order) (PAGE_SIZE << (order))
+#define READ_BUFFER_PAGE_ORDER 5
+#define READ_BUFFER_SIZE size_of_pages(READ_BUFFER_PAGE_ORDER)
+
+struct hone_reader {
+	struct semaphore sem;
+	struct ring_buf ringbuf;
+	struct notifier_block nb;
+	struct reader_info info;
+	atomic_t flags;
+	char *buf;
+	struct sock *filter_sk;
+	struct hone_event *event;
+	size_t length, offset;
+	wait_queue_head_t event_wait_queue;
+
+	unsigned int (*format)(const struct device_info*,
+			const struct reader_info*,
+			struct hone_event *,
+			char *, unsigned int);
+};
+
+static struct hone_event head_event = {HONE_USER_HEAD, {ATOMIC_INIT(1)} };
+static struct hone_event tail_event = {HONE_USER_TAIL, {ATOMIC_INIT(1)} };
+
+#define reader_will_block(rdr)					\
+	(ring_is_empty(&(rdr)->ringbuf) && !(rdr)->event &&	\
+	 !(atomic_read(&(rdr)->flags) & READER_RESTART))
+
+static unsigned int format_as_text(const struct device_info *devinfo,
+				const struct reader_info *info,
+				struct hone_event *event, char *buf,
+				unsigned int buflen)
+{
+	static const char * const event_names[] = {
+		"????", "FORK", "EXEC", "EXIT", "KTHD"};
+	unsigned int n = 0;
+
+#define printbuf(fmt, ...)						\
+	({								\
+		n += snprintf(buf + n, buflen - n, fmt, ##__VA_ARGS__); \
+		if (n >= buflen)					\
+			goto out_long;					\
+		n;							\
+	})
+
+	switch (event->type) {
+	case HONE_PROCESS:
+	{
+		struct process_event *pev = &event->process;
+
+		printbuf("%lu.%09lu %s %d %d %d %d\n",
+			event->ts.tv_sec, event->ts.tv_nsec,
+			event_names[pev->event], pev->pid, pev->ppid, pev->euid,
+			pev->gid);
+
+		if (pev->mm) {
+			n--;
+			if (pev->event == PROC_KTHD)
+				printbuf(" [%s]", pev->comm);
+			else {
+				char *path, *argv;
+
+				printbuf(" \"");
+				path = mm_path(pev->mm, buf + n,
+					buflen - n - 3);
+
+				if (path) {
+					int pathlen = strlen(path);
+
+					memmove(buf + n, path, pathlen);
+					n += pathlen;
+				}
+
+				printbuf("\" ");
+				argv = buf + n;
+				n += mm_argv(pev->mm, buf + n, buflen - n - 1);
+				for ( ; argv < buf + n; argv++) {
+					if (*argv == '\0')
+						*argv = ' ';
+				}
+			}
+			printbuf("\n");
+		}
+		break;
+	}
+	case HONE_SOCKET:
+	{
+		struct socket_event *sockev = &event->socket;
+
+		printbuf("%lu.%09lu SOCK %c %d %d %d %d %08lx\n",
+			event->ts.tv_sec, event->ts.tv_nsec,
+			sockev->event ? 'C' : 'O', sockev->pid, sockev->ppid,
+			sockev->uid, sockev->gid, sockev->sock & 0xFFFFFFFF);
+	}
+		break;
+	case HONE_PACKET:
+	{
+		int offset;
+		struct iphdr _iph, *iph;
+
+		offset = skb_network_offset(event->packet.skb);
+		iph = skb_header_pointer(event->packet.skb, offset,
+					sizeof(_iph), &_iph);
+
+		printbuf("%lu.%09lu PAKT %c %08lx %u", event->ts.tv_sec,
+			event->ts.tv_nsec, event->packet.dir ? 'I' : 'O',
+			event->packet.sock & 0xFFFFFFFF, event->packet.pid);
+		if (!iph)
+			printbuf(" ? ? -> ?");
+		else if (iph->version == 4) {
+			if (iph->protocol == IPPROTO_TCP ||
+				iph->protocol == IPPROTO_UDP) {
+				struct udphdr _uh, *uh;
+
+				uh = skb_header_pointer(
+					event->packet.skb,
+					offset + (iph->ihl << 2),
+					sizeof(_uh), &_uh);
+				if (uh) {
+					printbuf(" %sv4 %pI4:%d -> %pI4:%d",
+						iph->protocol == IPPROTO_TCP
+						? "TCP" : "UDP",
+						&iph->saddr, ntohs(uh->source),
+						&iph->daddr, ntohs(uh->dest));
+				} else {
+					printbuf(" %sv4 ? -> ?",
+						iph->protocol == IPPROTO_TCP ?
+						"TCP" : "UDP");
+				}
+			} else {
+				printbuf(" %u %pI4 -> %pI4", iph->protocol,
+					&iph->saddr, &iph->daddr);
+			}
+		} else if (iph->version == 6) {
+			struct ipv6hdr _iph6, *iph6;
+
+			iph6 = skb_header_pointer(event->packet.skb, offset,
+						sizeof(_iph6), &_iph6);
+			if (iph6->nexthdr == IPPROTO_TCP ||
+				iph6->nexthdr == IPPROTO_UDP) {
+				struct udphdr _uh, *uh;
+
+				uh = skb_header_pointer(
+					event->packet.skb,
+					offset + sizeof(struct ipv6hdr),
+					sizeof(_uh), &_uh);
+				if (uh) {
+					printbuf(" %sv6 %pI6:%d -> %pI6:%d",
+						iph6->nexthdr == IPPROTO_TCP ?
+						"TCP" : "UDP",
+						&iph6->saddr, ntohs(uh->source),
+						&iph6->daddr, ntohs(uh->dest));
+				} else {
+					printbuf(" %sv6 ? -> ?",
+						iph6->nexthdr == IPPROTO_TCP ?
+						"TCP" : "UDP");
+				}
+			} else {
+				printbuf(" %u %pI6 -> %pI6", iph6->nexthdr,
+					&iph6->saddr, &iph6->daddr);
+			}
+		} else {
+			printbuf(" ?.%d ? -> ?", iph->version);
+		}
+		printbuf(" %u\n", event->packet.skb->len);
+	}
+	break;
+	case HONE_USER_HEAD:
+		if (devinfo->host_guid_is_set)
+			printbuf("%lu.%09lu HEAD %lu.%09lu {" GUID_FMT "}\n",
+				info->start_time.tv_sec,
+				info->start_time.tv_nsec,
+				info->boot_time.tv_sec, info->boot_time.tv_nsec,
+				GUID_TUPLE(&devinfo->host_guid));
+		else
+			printbuf("%lu.%09lu HEAD %lu.%09lu\n",
+				info->start_time.tv_sec,
+				info->start_time.tv_nsec,
+				info->boot_time.tv_sec,
+				info->boot_time.tv_nsec);
+		break;
+	case HONE_USER_TAIL:
+		printbuf("%lu.%09lu TAIL\n",
+			info->start_time.tv_sec, info->start_time.tv_nsec);
+		break;
+	default:
+		printbuf("%lu.%09lu ???? %d\n",
+			 event->ts.tv_sec, event->ts.tv_nsec, event->type);
+		break;
+
+	}
+
+#undef printbuf
+	return n;
+out_long:
+	snprintf(buf + buflen - 5, 5, "...\n");
+	return buflen;
+}
+
+static void free_hone_reader(struct hone_reader *reader)
+{
+	if (reader) {
+		if (reader->ringbuf.data) {
+			free_pages((unsigned long) (reader->ringbuf.data),
+				   reader->ringbuf.pageorder);
+			reader->ringbuf.data = NULL;
+		}
+		if (reader->buf) {
+			free_pages((unsigned long) (reader->buf),
+				   READ_BUFFER_PAGE_ORDER);
+			reader->buf = NULL;
+		}
+		kfree(reader);
+	}
+}
+
+static struct hone_reader *alloc_hone_reader(void)
+{
+	struct hone_reader *reader;
+	struct ring_buf *ring;
+
+	reader = kzalloc(sizeof(*reader), GFP_KERNEL);
+	if (!reader)
+		goto alloc_failed;
+
+	reader->buf = (typeof(reader->buf)) __get_free_pages(
+		GFP_KERNEL | __GFP_ZERO, READ_BUFFER_PAGE_ORDER);
+	if (!reader->buf)
+		goto alloc_failed;
+
+	ring = &reader->ringbuf;
+	ring->pageorder = pageorder;
+
+	ring->data = (typeof(ring->data)) __get_free_pages(
+		GFP_KERNEL | __GFP_ZERO, ring->pageorder);
+	if (!ring->data)
+		goto alloc_failed;
+	ring->length = size_of_pages(ring->pageorder) / sizeof(*(ring->data));
+
+	reader->format = format_as_pcapng;
+
+	atomic_set(&reader->flags, READER_HEAD | READER_INIT);
+	sema_init(&reader->sem, 1);
+	init_waitqueue_head(&reader->event_wait_queue);
+	return reader;
+
+alloc_failed:
+	free_hone_reader(reader);
+	return NULL;
+}
+
+static void inc_stats_counter(struct statistics *stats, int type)
+{
+	atomic64_t *counter;
+
+	switch(type) {
+	case HONE_PROCESS:
+		counter = &stats->process;
+		break;
+	case HONE_SOCKET:
+		counter = &stats->socket;
+		break;
+	case HONE_PACKET:
+		counter = &stats->packet;
+		break;
+	default:
+		return;
+	}
+	atomic64_inc(counter);
+}
+
+static inline int enqueue_event(struct hone_reader *reader,
+				struct hone_event *event)
+{
+	/* Ignore threads for now */
+	if (event->type == HONE_PROCESS &&
+		event->process.pid != event->process.tgid)
+		return 0;
+	/* Filter out packets for local socket, if set */
+	if (event->type == HONE_PACKET && reader->filter_sk &&
+	    event->packet.sock == (unsigned long) reader->filter_sk) {
+		atomic64_inc(&reader->info.filtered);
+		return 0;
+	}
+
+	get_hone_event(event);
+	if (ring_append(&reader->ringbuf, event)) {
+		inc_stats_counter(&reader->info.dropped, event->type);
+		put_hone_event(event);
+		return 0;
+	}
+	return 1;
+}
+
+static int hone_event_handler(struct notifier_block *nb, unsigned long val,
+			      void *v)
+{
+	struct hone_reader *reader =
+		container_of(nb, struct hone_reader, nb);
+
+	if (enqueue_event(reader, v))
+		wake_up_interruptible_all(&reader->event_wait_queue);
+	return 0;
+}
+
+static struct hone_event *__add_files(struct hone_reader *reader,
+				      struct hone_event *event,
+				      struct task_struct *task)
+{
+	struct files_struct *files;
+	struct file *file;
+	struct fdtable *fdt;
+	struct hone_event *sk_event;
+	struct socket *sock;
+	struct sock *sk;
+	unsigned long flags, set;
+	int i, fd, err;
+
+	files = get_files_struct(task);
+	if (!files)
+		return event;
+
+	spin_lock_irqsave(&files->file_lock, flags);
+
+	fdt = files_fdtable(files);
+	if (!fdt)
+		goto out;
+
+	for (i = 0; (fd = i * BITS_PER_LONG) < fdt->max_fds; i++) {
+		for (set = fdt->open_fds[i]; set; set >>= 1, fd++) {
+			if (!(set & 1))
+				continue;
+			file = fdt->fd[fd];
+			if (!file)
+				continue;
+
+			sock = sock_from_file(file, &err);
+			if (!sock)
+				continue;
+			sk = sock->sk;
+			if (!sk || (sk->sk_family != PF_INET &&
+				    sk->sk_family != PF_INET6))
+				continue;
+
+			sk_event = __alloc_socket_event((unsigned long) sk,
+							0, task, GFP_ATOMIC);
+			if (sk_event) {
+				sk_event->next = event;
+				event = sk_event;
+				event->ts = task->start_time;
+			} else {
+				atomic64_inc(&reader->info.dropped.socket);
+			}
+		}
+	}
+out:
+	spin_unlock_irqrestore(&files->file_lock, flags);
+	put_files_struct(files);
+	return event;
+}
+
+#define prev_task(p) \
+	list_entry_rcu((p)->tasks.prev, struct task_struct, tasks)
+
+static struct hone_event *add_current_tasks(struct hone_reader *reader,
+					    struct hone_event *event)
+{
+	struct hone_event *proc_event;
+	struct task_struct *task;
+
+	rcu_read_lock();
+	for (task = &init_task; (task = prev_task(task)) != &init_task; ) {
+		if (task->flags & PF_EXITING)
+			continue;
+		event = __add_files(reader, event, task);
+		proc_event =  __alloc_process_event(
+			task, task->flags & PF_FORKNOEXEC ?
+			PROC_FORK : PROC_EXEC,
+			GFP_ATOMIC);
+		if (proc_event) {
+			proc_event->next = event;
+			event = proc_event;
+			event->ts = task->start_time;
+		} else {
+			atomic64_inc(&reader->info.dropped.process);
+		}
+	}
+	rcu_read_unlock();
+	return event;
+}
+
+static void free_initial_events(struct hone_reader *reader)
+{
+	struct hone_event *event, *next;
+
+	for (event = reader->event; event; event = next) {
+		next = event->next;
+		free_hone_event(event);
+	}
+	reader->event = NULL;
+}
+
+static void add_initial_events(struct hone_reader *reader)
+{
+	free_initial_events(reader);
+	reader->event = add_current_tasks(reader, NULL);
+}
+
+static int hone_open(struct inode *inode, struct file *file)
+{
+	struct hone_reader *reader;
+	int err = -ENOMEM;
+
+	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+		pr_err("no readonly failed\n");
+		return -EINVAL;
+	}
+
+	reader = alloc_hone_reader();
+	if (!reader) {
+		pr_err("reader alloc failed\n");
+		goto reader_failed;
+	}
+
+	if (file->f_dentry == devinfo.text)
+		reader->format = format_as_text;
+	file->private_data = reader;
+
+	getboottime(&reader->info.boot_time);
+	ktime_get_ts(&reader->info.start_time);
+	init_statistics(&reader->info.delivered);
+	init_statistics(&reader->info.dropped);
+	reader->nb.notifier_call = hone_event_handler;
+	err = hone_notifier_register(&reader->nb);
+	if (err) {
+		pr_err("hone_notifier_register() failed with error %d\n", err);
+		goto register_failed;
+	}
+	return 0;
+
+register_failed:
+	free_hone_reader(reader);
+reader_failed:
+	return err;
+}
+
+static int hone_release(struct inode *inode, struct file *file)
+{
+	struct hone_reader *reader = file->private_data;
+	struct hone_event *event;
+
+	hone_notifier_unregister(&reader->nb);
+	file->private_data = NULL;
+	while ((event = ring_pop(&reader->ringbuf)))
+		put_hone_event(event);
+	if (reader->filter_sk) {
+		sock_put(reader->filter_sk);
+		reader->filter_sk = NULL;
+	}
+	free_initial_events(reader);
+	free_hone_reader(reader);
+	return 0;
+}
+
+static ssize_t hone_read(struct file *file, char __user *buffer,
+			size_t length, loff_t *offset)
+{
+	struct hone_reader *reader = file->private_data;
+	size_t n, copied = 0;
+
+	if (!length)
+		return 0;
+
+	do {
+		while (!reader->offset && reader_will_block(reader)) {
+			if (file->f_flags & O_NONBLOCK)
+				return -EAGAIN;
+			if (wait_event_interruptible(
+					reader->event_wait_queue,
+					!reader_will_block(reader)))
+				return -EINTR;
+		}
+
+		if (file->f_flags & O_NONBLOCK) {
+			if (down_trylock(&reader->sem))
+				return -EAGAIN;
+		} else if (down_interruptible(&reader->sem)) {
+			return -EINTR;
+		}
+
+		while (copied < length) {
+			if (!reader->offset) {
+				int flags;
+				struct hone_event *event;
+
+				void (*free_event)(struct hone_event *);
+
+				flags = atomic_read(&reader->flags);
+				if (flags & READER_TAIL) {
+					atomic_clear_mask(READER_TAIL,
+							   &reader->flags);
+					 event = &tail_event;
+					 free_event = NULL;
+				} else if (flags & READER_FINISH) {
+					if (!copied)
+						atomic_clear_mask(READER_FINISH,
+								&reader->flags);
+					up(&reader->sem);
+					return copied;
+				} else if (flags & READER_HEAD) {
+					atomic_clear_mask(READER_HEAD,
+							  &reader->flags);
+					event = &head_event;
+					free_event = NULL;
+				} else if (flags & READER_INIT) {
+					atomic_clear_mask(READER_INIT,
+							  &reader->flags);
+					add_initial_events(reader);
+					continue;
+				} else if (reader->event) {
+					event = reader->event;
+					reader->event = event->next;
+					free_event = free_hone_event;
+				} else {
+					event = ring_pop(&reader->ringbuf);
+					free_event = put_hone_event;
+				}
+
+				if (!event)
+					break;
+				reader->length = reader->format(
+					&devinfo, &reader->info,
+					event, reader->buf, READ_BUFFER_SIZE);
+				inc_stats_counter(&reader->info.delivered,
+						event->type);
+				if (free_event)
+					free_event(event);
+			}
+			n = min(reader->length - reader->offset,
+				length - copied);
+			if (copy_to_user(buffer + copied,
+					 reader->buf + reader->offset, n)) {
+				up(&reader->sem);
+				return -EFAULT;
+			}
+			copied += n;
+			reader->offset += n;
+			if (reader->offset >= reader->length)
+				reader->offset = 0;
+		}
+		up(&reader->sem);
+	} while (!copied);
+	return copied;
+}
+
+static unsigned int hone_poll(struct file *file,
+			struct poll_table_struct *wait)
+{
+	struct hone_reader *reader = file->private_data;
+
+	poll_wait(file, &reader->event_wait_queue, wait);
+	if (!reader_will_block(reader))
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static const struct file_operations hone_ops = {
+	.open = hone_open,
+	.read = hone_read,
+	.release = hone_release,
+	.poll = hone_poll,
+};
+
+int __init hone_fs_init(void)
+{
+	devinfo.dir = securityfs_create_dir("hone", NULL);
+	if (IS_ERR(devinfo.dir))
+		return -1;
+	devinfo.pcapng = securityfs_create_file("pcapng", 0600,
+					devinfo.dir, NULL, &hone_ops);
+	if (!devinfo.pcapng) {
+		pr_err("could not create hone output file\n");
+		return -1;
+	}
+
+	devinfo.text = securityfs_create_file("text", 0600,
+					devinfo.dir, NULL, &hone_ops);
+	if (!devinfo.text) {
+		pr_err("could not create hone output file\n");
+		return -1;
+	}
+	return 0;
+}
diff --git a/security/hone/hone_lsm.c b/security/hone/hone_lsm.c
new file mode 100644
index 0000000..4f7e785
--- /dev/null
+++ b/security/hone/hone_lsm.c
@@ -0,0 +1,183 @@
+#include <linux/security.h>
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/sched.h>
+#include <linux/binfmts.h>
+#include <linux/netfilter.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+
+#include "hone.h"
+
+void hone_task_post_create(struct task_struct *task)
+{
+	process_notifier_notify(PROC_FORK, task);
+}
+
+void hone_task_free(struct task_struct *task)
+{
+	process_notifier_notify(PROC_EXIT, task);
+}
+
+void hone_bprm_committing_creds(struct linux_binprm *bprm)
+{
+	process_notifier_notify(PROC_EXEC, current);
+}
+
+int hone_socket_post_create(struct socket *sock, int family,
+			int type, int protocol, int kern)
+{
+	if (likely(sock->sk)) {
+		sock->sk->sk_protinfo = (void *)(unsigned long)
+			(current->pid == current->tgid ?
+				current->pid : current->tgid);
+		sock_notifier_notify(0, sock->sk);
+	}
+	return 0;
+}
+
+int hone_socket_shutdown(struct socket *sock, int how)
+{
+	sock_notifier_notify(0xFFFFFFFF, sock->sk);
+	return 0;
+}
+
+int hone_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+	struct packet_args pargs = {sk, skb};
+
+	switch (sk->sk_family) {
+	case PF_INET:
+	case PF_INET6:
+		packet_notifier_notify(PKTNOT_PACKET_IN, &pargs);
+	}
+	return 0;
+}
+
+static struct security_operations hone_ops = {
+	.name = "hone",
+
+	/* Process events. */
+	.task_post_create	= hone_task_post_create,
+	.task_free		= hone_task_free,
+	.bprm_committing_creds	= hone_bprm_committing_creds,
+
+	/* Socket events. */
+	.socket_post_create	= hone_socket_post_create,
+	.socket_shutdown	= hone_socket_shutdown,
+};
+
+static unsigned int nf_hook_v4_in(
+	const struct nf_hook_ops *hook, struct sk_buff *skb,
+	const struct net_device *indev, const struct net_device *outdev,
+	int (*okfn)(struct sk_buff *))
+{
+	struct sock *sk = lookup_v4_sock(skb, indev);
+	struct packet_args pargs = {sk, skb};
+
+	packet_notifier_notify(PKTNOT_PACKET_IN, &pargs);
+	if (sk)
+		put_sock(sk);
+	return NF_ACCEPT;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static unsigned int nf_hook_v6_in(
+	const struct nf_hook_ops *hook, struct sk_buff *skb,
+	const struct net_device *indev, const struct net_device *outdev,
+	int (*okfn)(struct sk_buff *))
+{
+	struct sock *sk = lookup_v6_sock(skb, indev);
+	struct packet_args pargs = {sk, skb};
+
+	packet_notifier_notify(PKTNOT_PACKET_IN, &pargs);
+	if (sk)
+		put_sock(sk);
+	return NF_ACCEPT;
+}
+#endif
+
+static unsigned int nf_hook_out(
+	const struct nf_hook_ops *hook, struct sk_buff *skb,
+	const struct net_device *indev, const struct net_device *outdev,
+	int (*okfn)(struct sk_buff *))
+{
+	struct packet_args pargs = {skb->sk, skb};
+
+	packet_notifier_notify(PKTNOT_PACKET_OUT, &pargs);
+	return NF_ACCEPT;
+}
+
+static struct nf_hook_ops nf_inet_hooks[] = {
+	{
+		.list = {NULL, NULL},
+		.hook = nf_hook_v4_in,
+		.owner = THIS_MODULE,
+		.pf = PF_INET,
+		.hooknum = NF_INET_LOCAL_IN,
+		.priority = INT_MAX,
+	},
+	{
+		.list = {NULL, NULL},
+		.hook = nf_hook_out,
+		.owner = THIS_MODULE,
+		.pf = PF_INET,
+		.hooknum = NF_INET_LOCAL_OUT,
+		.priority = INT_MAX,
+	},
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	{
+		.list = {NULL, NULL},
+		.hook = nf_hook_v6_in,
+		.owner = THIS_MODULE,
+		.pf = PF_INET6,
+		.hooknum = NF_INET_LOCAL_IN,
+		.priority = INT_MAX,
+	},
+	{
+		.list = {NULL, NULL},
+		.hook = nf_hook_out,
+		.owner = THIS_MODULE,
+		.pf = PF_INET6,
+		.hooknum = NF_INET_LOCAL_OUT,
+		.priority = INT_MAX,
+	},
+#endif /* CONFIG_IPV6 */
+};
+
+void hone_raw_rcv_handler(struct sock *sk, struct sk_buff *skb)
+{
+	struct packet_args pargs = {sk, skb};
+
+	packet_notifier_notify(PKTNOT_PACKET_IN, &pargs);
+}
+
+static __init int hone_net_init(void)
+{
+	int err = nf_register_hooks(nf_inet_hooks, ARRAY_SIZE(
+					nf_inet_hooks));
+	if (err) {
+		pr_err("netfilter hook registration failed (%d)\n", err);
+		return -1;
+	}
+	return 0;
+}
+
+static __init int hone_init(void)
+{
+	int ret;
+
+	if (!security_module_enable(&hone_ops))
+		return 0;
+
+	if (register_security(&hone_ops))
+		panic("hone: kernel registration failed\n");
+
+	ret = hone_notify_init() || hone_net_init() || hone_fs_init();
+	if (!ret)
+		pr_info("hone: initialized\n");
+	return ret;
+}
+
+late_initcall(hone_init);
diff --git a/security/hone/hone_mmutil.c b/security/hone/hone_mmutil.c
new file mode 100644
index 0000000..bfdb72b
--- /dev/null
+++ b/security/hone/hone_mmutil.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ *
+ * Much of the code below is based on procfs code.
+ */
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/mount.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+
+static int __mm_argv(struct mm_struct *mm, char *buf, int buflen)
+{
+	char *pos;
+	unsigned long addr, size;
+
+	if (!buflen)
+		return 0;
+
+	pos = buf;
+	addr = mm->arg_start;
+	size = mm->arg_end - mm->arg_start;
+	if (size > buflen)
+		size = buflen;
+	while (size) {
+		struct page *page;
+		int bytes, offset;
+		void *maddr;
+
+		if (get_user_pages(NULL, mm, addr, 1, 0, 0, &page, NULL) <= 0)
+			break;
+
+		bytes = size;
+		offset = addr & (PAGE_SIZE - 1);
+		if (bytes > (PAGE_SIZE - offset))
+			bytes = PAGE_SIZE - offset;
+
+		maddr = kmap(page);
+		memcpy(pos, maddr + offset, bytes);
+		kunmap(page);
+		put_page(page);
+
+		size -= bytes;
+		pos += bytes;
+		addr += bytes;
+	}
+
+	if (pos == buf) {
+		*pos = '\0';
+		pos++;
+	} else if (*(pos - 1))
+		*(pos - 1) = '\0';
+	return pos - buf;
+}
+
+int mm_argv(struct mm_struct *mm, char *buf, int buflen)
+{
+	int argvlen;
+
+	down_read(&mm->mmap_sem);
+	argvlen = __mm_argv(mm, buf, buflen - 1);
+	up_read(&mm->mmap_sem);
+	buf[argvlen] = '\0';
+	return argvlen;
+}
+
+static char *__exe_path(struct mm_struct *mm, char *buf, int buflen)
+{
+	char *path = NULL;
+
+	if (mm->exe_file) {
+		struct vfsmount *mnt;
+		struct dentry *dentry;
+
+		mnt = mntget(mm->exe_file->f_path.mnt);
+		dentry = dget(mm->exe_file->f_path.dentry);
+
+		if (mnt && dentry) {
+			struct path _p = {mnt, dentry};
+
+			path = d_path(&_p, buf, buflen);
+			dput(dentry);
+			mntput(mnt);
+		}
+	}
+	return path;
+}
+
+char *mm_path(struct mm_struct *mm, char *buf, int buflen)
+{
+	char *path;
+
+	down_read(&mm->mmap_sem);
+	path = __exe_path(mm, buf, buflen);
+	up_read(&mm->mmap_sem);
+	return path;
+}
diff --git a/security/hone/hone_mmutil.h b/security/hone/hone_mmutil.h
new file mode 100644
index 0000000..321e7e6
--- /dev/null
+++ b/security/hone/hone_mmutil.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ */
+
+#ifndef _MMUTIL_H
+#define _MMUTIL_H
+
+#include <linux/mm_types.h>
+
+char *mm_path(struct mm_struct *mm, char *buf, int buflen);
+char *mm_path_old(struct mm_struct *mm, char *buf, int buflen);
+int mm_argv(struct mm_struct *mm, char *buf, int buflen);
+
+#endif /* _MMUTIL_H */
diff --git a/security/hone/hone_notify.c b/security/hone/hone_notify.c
new file mode 100644
index 0000000..08c2f8f
--- /dev/null
+++ b/security/hone/hone_notify.c
@@ -0,0 +1,450 @@
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/skbuff.h>
+#include <linux/cred.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/workqueue.h>
+#include <linux/uidgid.h>
+#include <net/sock.h>
+#include <linux/hone.h>
+
+#include "hone.h"
+
+/* Output */
+static RAW_NOTIFIER_HEAD(hone_notify_notifier_list);
+static DEFINE_RWLOCK(hone_notify_notifier_lock);
+
+/* Process list/Process lock. */
+static RAW_NOTIFIER_HEAD(hone_process_notifier_list);
+static DEFINE_RWLOCK(hone_process_notifier_lock);
+
+/* Socket list/Socket lock. */
+static RAW_NOTIFIER_HEAD(hone_socket_notifier_list);
+static DEFINE_RWLOCK(hone_socket_notifier_lock);
+
+/* Packet list/Packet lock. */
+static RAW_NOTIFIER_HEAD(hone_packet_notifier_list);
+static DEFINE_RWLOCK(hone_packet_notifier_lock);
+
+static struct kmem_cache *hone_cache;
+static struct kmem_cache *mmput_cache;
+static struct workqueue_struct *mmput_wq;
+struct delayed_mmput_struct {
+	struct work_struct ws;
+	struct mm_struct *mm;
+};
+
+static struct timespec start_time;
+static DEFINE_STATISTICS(hone_received);
+static DEFINE_STATISTICS(hone_dropped);
+
+#define copy_atomic64(dst, src) atomic64_set(&(dst), atomic64_read(&(src)))
+
+static void copy_statistics(const struct statistics *src,
+			struct statistics *dst)
+{
+	copy_atomic64(dst->process, src->process);
+	copy_atomic64(dst->socket, src->socket);
+	copy_atomic64(dst->packet, src->packet);
+}
+
+void get_hone_statistics(struct statistics *received,
+			struct statistics *dropped, struct timespec *ts)
+{
+	if (received)
+		copy_statistics(&hone_received, received);
+	if (dropped)
+		copy_statistics(&hone_dropped, dropped);
+	if (ts)
+		*ts = start_time;
+}
+
+#define notifier_call_chain_empty() \
+	(rcu_dereference(hone_notify_notifier_list.head) == NULL)
+
+static inline int hone_notifier_notify(struct hone_event *event)
+{
+	int result;
+	unsigned long flags;
+
+	read_lock_irqsave(&hone_notify_notifier_lock, flags);
+	result = raw_notifier_call_chain(&hone_notify_notifier_list, 0, event);
+	read_unlock_irqrestore(&hone_notify_notifier_lock, flags);
+	return result;
+}
+
+static void delayed_mmput(struct work_struct *work)
+{
+	struct delayed_mmput_struct *w = (struct delayed_mmput_struct *)work;
+
+	mmput(w->mm);
+	kmem_cache_free(mmput_cache, w);
+}
+
+static bool queue_mmput(struct mm_struct *mm)
+{
+	struct delayed_mmput_struct *delayed_mm =
+		kmem_cache_zalloc(mmput_cache, GFP_ATOMIC);
+
+	if (!delayed_mm)
+		return false;
+
+	delayed_mm->mm = mm;
+	INIT_WORK((struct work_struct *)delayed_mm,
+		delayed_mmput);
+
+	return queue_work(mmput_wq, (struct work_struct *)delayed_mm);
+}
+
+void free_hone_event(struct hone_event *event)
+{
+	if (event->type == HONE_PROCESS) {
+		if (event->process.mm) {
+			if (event->process.event == PROC_KTHD) {
+				kfree(event->process.comm);
+			} else {
+				if (unlikely(!queue_mmput(event->process.mm)))
+					BUG();
+			}
+			event->process.mm = NULL;
+		}
+	}
+	kmem_cache_free(hone_cache, event);
+}
+
+struct hone_event *alloc_hone_event(unsigned int type, gfp_t flags)
+{
+	struct hone_event *event;
+
+	event = kmem_cache_zalloc(hone_cache, flags);
+	if (!event)
+		return NULL;
+	event->type = type;
+	ktime_get_ts(&event->ts);
+	atomic_set(&event->users, 1);
+	return event;
+}
+
+struct hone_event *__alloc_process_event(
+	struct task_struct *task, int type, gfp_t flags)
+{
+	struct hone_event *event;
+
+	event = alloc_hone_event(HONE_PROCESS, flags);
+	if (event) {
+		struct process_event *pev = &event->process;
+		const struct cred *cred;
+
+		pev->event = (type != PROC_EXIT && task->flags & PF_KTHREAD) ?
+			PROC_KTHD : type;
+		if (unlikely(type == PROC_EXIT))
+			pev->retval = task->exit_code;
+		pev->pid = task->pid;
+		pev->ppid = task->real_parent->pid;
+		pev->tgid = task->tgid;
+		if (pev->event == PROC_KTHD) {
+			pev->comm = kstrndup(task->comm,
+					sizeof(task->comm), flags);
+			BUG_ON(unlikely(!pev->comm));
+		} else if (type == PROC_EXEC ||
+			(type == PROC_FORK && pev->ppid == 1)) {
+			pev->mm = get_task_mm(task);
+			BUG_ON(unlikely(!pev->mm));
+		}
+		pev->loginuid = __kuid_val(task->loginuid);
+		rcu_read_lock();
+		cred = __task_cred(task);
+		if (unlikely(!cred)) {
+			pev->uid = -1;
+			pev->euid = -1;
+		} else {
+			pev->uid = __kuid_val(cred->uid);
+			pev->euid = __kuid_val(cred->euid);
+		}
+		pev->gid = __kgid_val(cred->egid);
+		rcu_read_unlock();
+	}
+	return event;
+}
+
+int process_notifier_notify(unsigned long event, struct task_struct *task)
+{
+	int result;
+	unsigned long flags;
+
+	read_lock_irqsave(&hone_process_notifier_lock, flags);
+	result = raw_notifier_call_chain(&hone_process_notifier_list, event,
+					task);
+	read_unlock_irqrestore(&hone_process_notifier_lock, flags);
+	return result;
+}
+
+static int process_event_handler(struct notifier_block *nb,
+				 unsigned long val, void *v)
+{
+	struct hone_event *event;
+
+	if (notifier_call_chain_empty())
+		return 0;
+
+	event = __alloc_process_event(v, val, GFP_ATOMIC);
+	if (event) {
+		atomic64_inc(&hone_received.process);
+		hone_notifier_notify(event);
+		put_hone_event(event);
+	} else {
+		atomic64_inc(&hone_dropped.process);
+	}
+	return 0;
+}
+
+static struct notifier_block process_nb = {
+	.notifier_call = process_event_handler,
+};
+
+/* Process sockets below here. */
+struct hone_event *__alloc_socket_event(unsigned long sock, int type,
+					struct task_struct *task, gfp_t flags)
+{
+	struct hone_event *event;
+
+	event = alloc_hone_event(HONE_SOCKET, flags);
+	if (event) {
+		struct socket_event *sockev = &event->socket;
+		const struct cred *cred;
+
+		/* Store pid with the socket */
+		((struct sock *)sock)->sk_protinfo =
+			(void *)(unsigned long)task->pid;
+		sockev->sock = sock;
+		sockev->event = type;
+		sockev->pid = task->pid;
+		sockev->ppid = task->real_parent->pid;
+		sockev->tgid = task->tgid;
+		rcu_read_lock();
+		cred = __task_cred(task);
+		if (unlikely(!cred)) {
+			sockev->uid = -1;
+			sockev->gid = -1;
+		} else {
+			sockev->uid = __kuid_val(cred->euid);
+			sockev->gid = __kgid_val(cred->egid);
+		}
+		rcu_read_unlock();
+	}
+	return event;
+}
+
+static int socket_event_handler(struct notifier_block *nb,
+				unsigned long val, void *v)
+{
+	struct hone_event *event;
+
+	if (notifier_call_chain_empty())
+		return 0;
+	event = __alloc_socket_event((unsigned long) v, val, current,
+				GFP_ATOMIC);
+	if (event) {
+		atomic64_inc(&hone_received.socket);
+		hone_notifier_notify(event);
+		put_hone_event(event);
+	} else {
+		atomic64_inc(&hone_dropped.socket);
+	}
+	return 0;
+}
+
+static struct notifier_block socket_nb = {
+	.notifier_call = socket_event_handler,
+};
+
+int sock_notifier_register(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_socket_notifier_lock, flags);
+	result = raw_notifier_chain_register(&hone_socket_notifier_list, nb);
+	write_unlock_irqrestore(&hone_socket_notifier_lock, flags);
+	return result;
+}
+
+int sock_notifier_unregister(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_socket_notifier_lock, flags);
+	result = raw_notifier_chain_unregister(&hone_socket_notifier_list, nb);
+	write_unlock_irqrestore(&hone_socket_notifier_lock, flags);
+	return result;
+}
+
+inline int sock_notifier_notify(unsigned long event, struct sock *sk)
+{
+	int result;
+	unsigned long flags;
+
+	read_lock_irqsave(&hone_socket_notifier_lock, flags);
+	result = raw_notifier_call_chain(&hone_socket_notifier_list, event, sk);
+	read_unlock_irqrestore(&hone_socket_notifier_lock, flags);
+	return result;
+}
+
+static int packet_event_handler(struct notifier_block *nb,
+				unsigned long val, void *v)
+{
+	struct hone_event *event;
+
+	if (notifier_call_chain_empty())
+		return 0;
+
+	event = alloc_hone_event(HONE_PACKET, GFP_ATOMIC);
+	if (event) {
+		struct packet_args *args = (typeof(args)) v;
+
+		event->packet.sock = (unsigned long) args->sk;
+		event->packet.sk = args->sk;
+		event->packet.pid =
+			(unsigned long)(args->sk ? args->sk->sk_protinfo : 0);
+		event->packet.skb = skb_clone(args->skb, GFP_ATOMIC);
+		event->packet.dir = (val == PKTNOT_PACKET_IN);
+		atomic64_inc(&hone_received.packet);
+		hone_notifier_notify(event);
+		put_hone_event(event);
+	} else {
+		atomic64_inc(&hone_dropped.packet);
+	}
+	return 0;
+}
+
+static struct notifier_block packet_nb = {
+	.notifier_call = packet_event_handler,
+};
+
+int packet_notifier_register(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_packet_notifier_lock, flags);
+	result = raw_notifier_chain_register(&hone_packet_notifier_list, nb);
+	write_unlock_irqrestore(&hone_packet_notifier_lock, flags);
+	return result;
+}
+
+int packet_notifier_unregister(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_packet_notifier_lock, flags);
+	result = raw_notifier_chain_unregister(&hone_packet_notifier_list, nb);
+	write_unlock_irqrestore(&hone_packet_notifier_lock, flags);
+	return result;
+}
+
+int packet_notifier_notify(
+	unsigned long event, struct packet_args *pargs)
+{
+	int result;
+	unsigned long flags;
+
+	read_lock_irqsave(&hone_packet_notifier_lock, flags);
+	result = raw_notifier_call_chain(&hone_packet_notifier_list,
+					event, pargs);
+	read_unlock_irqrestore(&hone_packet_notifier_lock, flags);
+	return result;
+}
+
+void register_notifiers(void)
+{
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_process_notifier_lock, flags);
+	/* TODO(pmoody): check return values. */
+	raw_notifier_chain_register(&hone_process_notifier_list,
+				&process_nb);
+	raw_notifier_chain_register(&hone_socket_notifier_list,
+				&socket_nb);
+	raw_notifier_chain_register(&hone_packet_notifier_list,
+				&packet_nb);
+	write_unlock_irqrestore(&hone_process_notifier_lock, flags);
+}
+
+void unregister_notifiers(void)
+{
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_process_notifier_lock, flags);
+	/* TODO(pmoody): check return values. */
+	raw_notifier_chain_unregister(&hone_process_notifier_list,
+				&process_nb);
+	raw_notifier_chain_unregister(&hone_socket_notifier_list,
+				&socket_nb);
+	raw_notifier_chain_unregister(&hone_packet_notifier_list,
+				&packet_nb);
+	write_unlock_irqrestore(&hone_process_notifier_lock, flags);
+}
+
+int hone_notifier_register(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_notify_notifier_lock, flags);
+	if (notifier_call_chain_empty())
+		register_notifiers();
+	result = raw_notifier_chain_register(&hone_notify_notifier_list, nb);
+	write_unlock_irqrestore(&hone_notify_notifier_lock, flags);
+	return result;
+}
+
+int hone_notifier_unregister(struct notifier_block *nb)
+{
+	int result;
+	unsigned long flags;
+
+	write_lock_irqsave(&hone_notify_notifier_lock, flags);
+	result = raw_notifier_chain_unregister(&hone_notify_notifier_list, nb);
+	if (notifier_call_chain_empty())
+		unregister_notifiers();
+	write_unlock_irqrestore(&hone_notify_notifier_lock, flags);
+	return result;
+}
+
+int __init hone_notify_init(void)
+{
+	int err = -ENOMEM;
+
+	hone_cache = kmem_cache_create(
+		"hone_event", sizeof(struct hone_event), 0, 0, NULL);
+	if (!hone_cache) {
+		pr_err("kmem_cache_create() failed\n");
+		goto out_hone_cache;
+	}
+
+	mmput_cache = kmem_cache_create(
+		"hone_delayed_mmput", sizeof(struct delayed_mmput_struct),
+		0, 0, NULL);
+	if (!mmput_cache) {
+		pr_err("kmem_cache_create() failed on delayed_mm_cache\n");
+		goto out_mmput_cache;
+	}
+
+	mmput_wq = create_workqueue("hone_mmput");
+	if (!mmput_wq) {
+		err = -1;
+		goto out_workqueue;
+	}
+
+	return 0;
+
+out_workqueue:
+	kmem_cache_destroy(mmput_cache);
+out_mmput_cache:
+	kmem_cache_destroy(hone_cache);
+out_hone_cache:
+	return err;
+}
diff --git a/security/hone/hone_pcapng.c b/security/hone/hone_pcapng.c
new file mode 100644
index 0000000..0c5347c
--- /dev/null
+++ b/security/hone/hone_pcapng.c
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ktime.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/rwsem.h>
+#include <linux/utsname.h>
+#include <linux/skbuff.h>
+#include <linux/hone.h>
+
+#include "hone.h"
+#include "hone_mmutil.h"
+
+#define PADLEN(x) (((x) & 0x3) ? 4 - ((x) & 3) : 0)
+#define OPT_SIZE(x) (((x) & 0x3) ? ((((x) >> 2) + 1) << 2) : x)
+#define block_set(BUF, TYPE, VAL) \
+	({ *((TYPE*) (BUF)) = (VAL); sizeof(TYPE); })
+
+static unsigned int block_opt_ptr(char *buf,
+		uint16_t code, const void *ptr, unsigned int length)
+{
+	char *pos = buf;
+	unsigned int padlen = PADLEN(length);
+
+	pos += block_set(pos, uint16_t, code);
+	pos += block_set(pos, uint16_t, length);
+	if (ptr)
+		memcpy(pos, ptr, length);
+	pos += length;
+	memset(pos, 0, padlen);
+	pos += padlen;
+	return (unsigned int) (pos - buf);
+}
+
+#define block_opt_t(BUF, CODE, TYPE, VAL) ({				\
+			TYPE _value = (VAL);				\
+			unsigned int _length =				\
+				block_opt_ptr(BUF, CODE, &_value,	\
+					sizeof(_value));		\
+			_length; })
+
+#define block_opt(BUF, CODE, VAL) block_opt_t(BUF, CODE, typeof(VAL), VAL)
+#define block_end_opt(BUF) block_opt_ptr(BUF, 0, NULL, 0)
+
+struct timestamp {
+	uint32_t ts_high;
+	uint32_t ts_low;
+};
+
+static void timespec_to_tstamp(struct timestamp *tstamp, struct timespec *ts)
+{
+	uint64_t val = (((uint64_t) ts->tv_sec) * 1000000LL) +
+		ts->tv_nsec / 1000;
+	tstamp->ts_high = val >> 32;
+	tstamp->ts_low = val & 0xFFFFFFFF;
+}
+
+/* Section Header Block {{{
+  0                   1                   2                   3
+   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                   Block Type = 0x0A0D0D0A                     |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |                      Byte-Order Magic                         |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |          Major Version        |         Minor Version         |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 |                                                               |
+   |                          Section Length                       |
+   |                                                               |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+24 /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static unsigned int format_sechdr_block(const struct device_info *devinfo,
+		char *buf, unsigned int buflen)
+{
+	static const char *user_app = "Hone ";
+	char *pos = buf;
+	unsigned int *length_top, *length_end;
+	int n;
+
+	/* Be sure to update this value if fields are added below. */
+#define SECHDR_BLOCK_MIN_LEN 56
+	if (buflen < SECHDR_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_SECTION_HDR_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t, 0x1A2B3C4D);
+	pos += block_set(pos, uint16_t, 1);
+	pos += block_set(pos, uint16_t, 0);
+	pos += block_set(pos, uint64_t, -1);
+
+	n = buflen - (pos - buf) - 16;
+	if (devinfo->host_id && n > 0) {
+		snprintf(pos + 4, n, "%c%s", 0, devinfo->host_id);
+		pos += block_opt_ptr(pos, 257, NULL, strlen(pos + 5) + 1);
+	} else if (devinfo->host_guid_is_set) {
+		memcpy(pos + 4, "\x01\x00\x00\x00", 4);
+		memcpy(pos + 8, &devinfo->host_guid,
+			sizeof(devinfo->host_guid));
+		pos += block_opt_ptr(pos, 257, NULL, 20);
+	}
+	n = buflen - (pos - buf) - 16;
+	if (n > 0) {
+		struct new_utsname *uname;
+
+		down_read(&uts_sem);
+		uname = utsname();
+		snprintf(pos + 4, n, "%s %s %s %s %s",
+				uname->sysname, uname->nodename, uname->release,
+				uname->version, uname->machine);
+		up_read(&uts_sem);
+		pos[n] = '\0';
+		pos += block_opt_ptr(pos, 3, NULL, strlen(pos + 4));
+	}
+	n = buflen - (pos - buf) - 16;
+	if (n > 0)
+		pos += block_opt_ptr(pos, 4, user_app,
+				min(n, (typeof(n)) strlen(user_app)));
+	n = buflen - (pos - buf) - 16;
+	if (devinfo->comment && n > 0) {
+		unsigned int i, j;
+
+		for (i = 0, j = 4; devinfo->comment[i] && j < n; i++, j++) {
+			if (devinfo->comment[i] == '\\' &&
+				(!strncmp(devinfo->comment + i + 1, "040", 3) ||
+					!strncmp(devinfo->comment + i + 1, "x20", 3))) {
+				pos[j] = ' ';
+				i += 3;
+			} else
+				pos[j] = devinfo->comment[i];
+		}
+		n = j - 4;
+		if (n)
+			pos += block_opt_ptr(pos, 1, NULL, n);
+	}
+	pos += block_end_opt(pos);
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+/* Interface Description Block {{{
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                    Block Type = 0x00000001                    |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |           LinkType            |           Reserved            |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |                            SnapLen                            |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static unsigned int format_ifdesc_block(const struct reader_info *info,
+		char *buf, int buflen)
+{
+	static const char *if_desc = "Hone Capture Pseudo-device";
+	char *pos = buf;
+	unsigned int *length_top, *length_end;
+
+	/* Be sure to update this value if fields are added below. */
+#define IFDESC_BLOCK_MIN_LEN 56
+	if (buflen < IFDESC_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_IF_DESC_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint16_t, 101);
+	pos += block_set(pos, uint16_t, 0);
+	pos += block_set(pos, uint32_t, info->snaplen);
+	pos += block_opt_ptr(pos, 3, if_desc,
+			strlen(if_desc));
+	pos += block_end_opt(pos);
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+/* Interface Statistics Block {{{
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                   Block Type = 0x00000005                     |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |                         Interface ID                          |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |                        Timestamp (High)                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 |                        Timestamp (Low)                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+20 /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static unsigned int format_ifstats_block(const struct reader_info *info,
+		char *buf, int buflen)
+{
+	char *pos = buf;
+	unsigned int *length_top, *length_end;
+	struct timespec ts;
+	struct timestamp tstamp, start_time;
+	struct statistics received, dropped;
+
+	get_hone_statistics(&received, &dropped, &ts);
+	set_normalized_timespec(&ts, info->boot_time.tv_sec + ts.tv_sec,
+			info->boot_time.tv_nsec + ts.tv_nsec);
+	timespec_to_tstamp(&start_time, &ts);
+	ktime_get_ts(&ts);
+	set_normalized_timespec(&ts, info->boot_time.tv_sec + ts.tv_sec,
+			info->boot_time.tv_nsec + ts.tv_nsec);
+	timespec_to_tstamp(&tstamp, &ts);
+
+	/* Be sure to update this value if fields are added below. */
+#define IFSTATS_BLOCK_MIN_LEN 196
+	if (buflen < IFSTATS_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_IF_STATS_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, struct timestamp, tstamp);
+	pos += block_opt_t(pos, 2, struct timestamp, start_time);
+	pos += block_opt_t(pos, 4, uint64_t, atomic64_read(&received.packet));
+	pos += block_opt_t(pos, 5, uint64_t, atomic64_read(&dropped.packet));
+	pos += block_opt_t(pos, 6, uint64_t, atomic64_read(&info->filtered));
+	pos += block_opt_t(pos, 7, uint64_t, atomic64_read(&info->dropped.packet));
+	pos += block_opt_t(pos, 8, uint64_t, atomic64_read(&info->delivered.packet));
+	pos += block_opt_t(pos, 257, uint64_t, atomic64_read(&received.process));
+	pos += block_opt_t(pos, 258, uint64_t, atomic64_read(&dropped.process));
+	pos += block_opt_t(pos, 259, uint64_t, atomic64_read(&info->dropped.process));
+	pos += block_opt_t(pos, 260, uint64_t, atomic64_read(&info->delivered.process));
+	pos += block_opt_t(pos, 261, uint64_t, atomic64_read(&received.socket));
+	pos += block_opt_t(pos, 262, uint64_t, atomic64_read(&dropped.socket));
+	pos += block_opt_t(pos, 263, uint64_t, atomic64_read(&info->dropped.socket));
+	pos += block_opt_t(pos, 264, uint64_t, atomic64_read(&info->delivered.socket));
+	pos += block_end_opt(pos);
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+static inline unsigned int maxoptlen(int buflen, unsigned int length)
+{
+	unsigned int alignlen = ((buflen - 16) >> 2) << 2;
+
+	if (unlikely(buflen < 0))
+		return 0;
+	return alignlen < length ? alignlen : length;
+}
+
+/* Process Event Block {{{
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                    Block Type = 0x00000101                    |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |                          Process ID                           |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |                        Timestamp (High)                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 |                        Timestamp (Low)                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+20 /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static size_t format_process_block(struct process_event *event,
+		struct timestamp *tstamp, char *buf, size_t buflen)
+{
+	static const uint32_t event_map[] = {0, 1, 0, -1, 2};
+	char *pos = buf;
+	unsigned int *length_top, *length_end;
+
+	/* Be sure to update this value if fields are added below. */
+#define PROCESS_BLOCK_MIN_LEN 56
+	if (buflen < PROCESS_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_PROCESS_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t, event->tgid);
+	pos += block_set(pos, struct timestamp, *tstamp);
+	if (event->event != PROC_EXEC)
+		pos += block_opt_t(pos, 2, uint32_t, event_map[event->event]);
+	pos += block_opt_t(pos, 5, uint32_t, event->ppid);
+	pos += block_opt_t(pos, 6, uint32_t, event->uid);
+	pos += block_opt_t(pos, 8, uint32_t, event->euid);
+	pos += block_opt_t(pos, 9, uint32_t, event->loginuid);
+	pos += block_opt_t(pos, 7, uint32_t, event->gid);
+	if (event->mm) {
+		char *tmp, *ptr;
+		unsigned int n, length;
+
+		ptr = pos + 4;
+		length = buflen - (pos - buf) - 16;
+		if (event->event == PROC_KTHD) {
+			n = strlen(event->comm);
+			length = maxoptlen(length, n + 2);
+			if (length) {
+				ptr[0] = '[';
+				if (length > 1)
+					memcpy(ptr + 1, event->comm,
+						length - 1);
+				if (length > n + 1)
+					ptr[length - 1] = ']';
+				pos += block_opt_ptr(pos, 3, NULL, length);
+			}
+		} else {
+			if (length > 0) {
+				tmp = mm_path(event->mm, ptr, length);
+				if (tmp) {
+					length = maxoptlen(length, strlen(tmp));
+					if (length) {
+						memmove(ptr, tmp, length);
+						pos += block_opt_ptr(pos, 3,
+								NULL, length);
+					}
+				}
+			}
+			ptr = pos + 4;
+			length = buflen - (pos - buf) - 16;
+			if (length > 0) {
+				n = mm_argv(event->mm, ptr, length);
+				if (n)
+					pos += block_opt_ptr(pos, 4, NULL,
+							maxoptlen(length, n));
+			}
+		}
+	}
+	pos += block_end_opt(pos);
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+/* Connection Event Block {{{
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                    Block Type = 0x00000102                    |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |                        Connection ID                          |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |                          Process ID                           |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 |                        Timestamp (High)                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+20 |                        Timestamp (Low)                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+24 /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static size_t format_connection_block(struct socket_event *event,
+		struct timestamp *tstamp, char *buf, size_t buflen)
+{
+	char *pos = buf;
+	unsigned int *length_top, *length_end;
+
+	/* Be sure to update this value if fields are added below. */
+#define CONNECTION_BLOCK_MIN_LEN 40
+	if (buflen < CONNECTION_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_CONNECTION_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t,
+			event->sock & 0xFFFFFFFF);
+	pos += block_set(pos, uint32_t, event->tgid);
+	pos += block_set(pos, struct timestamp, *tstamp);
+	if (event->event) {
+		pos += block_opt_t(pos, 2, uint32_t, -1);
+		pos += block_end_opt(pos);
+	}
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+/* Enhanced Packet Block {{{
+   0                   1                   2                   3
+   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +---------------------------------------------------------------+
+ 0 |                    Block Type = 0x00000006                    |
+   +---------------------------------------------------------------+
+ 4 |                      Block Total Length                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 |                         Interface ID                          |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 |                        Timestamp (High)                       |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 |                        Timestamp (Low)                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+20 |                         Captured Len                          |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+24 |                          Packet Len                           |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+28 /                                                               /
+   /                          Packet Data                          /
+   /           ( variable length, aligned to 32 bits )             /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   /                                                               /
+   /                      Options (variable)                       /
+   /                                                               /
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                      Block Total Length                       |
+   +---------------------------------------------------------------+
+}}} */
+static size_t format_packet_block(struct packet_event *event,
+				unsigned int snaplen,
+				struct timestamp *tstamp,
+				char *buf, size_t buflen)
+{
+	char *pos = buf;
+	int offset;
+	unsigned int *length_top, *length_end, *length_cap, offlen;
+	struct sk_buff *skb = event->skb;
+
+	/* Be sure to update this value if fields are added below. */
+#define PACKET_BLOCK_MIN_LEN 52
+	if (buflen < PACKET_BLOCK_MIN_LEN)
+		return 0;
+	pos += block_set(pos, uint32_t, HONE_PACKET_BLOCK);
+	length_top = (typeof(length_top)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, struct timestamp, *tstamp);
+	length_cap = (typeof(length_cap)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	pos += block_set(pos, uint32_t, event->len);
+
+	/* packet data */
+	offset = skb_network_header(skb) - skb->data;
+	offlen = snaplen ? min(skb->len - offset, snaplen) : skb->len - offset;
+	*length_cap = maxoptlen(buflen - (pos - buf), offlen);
+	if (*length_cap) {
+		unsigned int n = *length_cap & 3 ? 4 - (*length_cap & 3) : 0;
+
+		if (skb_copy_bits(skb, offset, pos, *length_cap))
+			BUG();
+		pos += *length_cap;
+		memset(pos, 0, n);
+		pos += n;
+	}
+
+	if (event->sock)
+		pos += block_opt_t(pos, 257, uint32_t,
+				event->sock & 0xFFFFFFFF);
+	if (event->pid)
+		pos += block_opt_t(pos, 258, uint32_t, event->pid);
+	pos += block_opt_t(pos, 2, uint32_t, event->dir ? 1 : 2);
+	pos += block_end_opt(pos);
+	length_end = (typeof(length_end)) pos;
+	pos += block_set(pos, uint32_t, 0);
+	*length_top = *length_end = (unsigned int) (pos - buf);
+	return *length_top;
+}
+
+static void normalize_ts(struct timestamp *tstamp,
+			const struct timespec *boot_time,
+			const struct timespec *event_time)
+{
+	struct timespec ts;
+
+	/* The following is used instead of timespec_add()
+	   because it doesn't exist in older kernel versions. */
+	set_normalized_timespec(&ts, boot_time->tv_sec + event_time->tv_sec,
+			boot_time->tv_nsec + event_time->tv_nsec);
+	timespec_to_tstamp(tstamp, &ts);
+}
+
+unsigned int format_as_pcapng(
+	const struct device_info *devinfo, const struct reader_info *info,
+	struct hone_event *event, char *buf, unsigned int buflen)
+{
+	unsigned int n = 0;
+	struct timestamp tstamp;
+
+	switch (event->type) {
+	case HONE_PACKET:
+		normalize_ts(&tstamp, &info->boot_time, &event->ts);
+		n = format_packet_block(
+			&event->packet, info->snaplen, &tstamp, buf, buflen);
+		break;
+	case HONE_PROCESS:
+		normalize_ts(&tstamp, &info->boot_time, &event->ts);
+		n = format_process_block(&event->process, &tstamp, buf, buflen);
+		break;
+	case HONE_SOCKET:
+		normalize_ts(&tstamp, &info->boot_time, &event->ts);
+		n = format_connection_block(&event->socket, &tstamp,
+					buf, buflen);
+		break;
+	case HONE_USER_HEAD:
+		n = format_sechdr_block(devinfo, buf, buflen);
+		n += format_ifdesc_block(info, buf + n, buflen - n);
+		break;
+	case HONE_USER_TAIL:
+		n = format_ifstats_block(info, buf + n, buflen - n);
+		break;
+	}
+
+	return n;
+}
+
+int parse_guid(struct guid_struct *guid, const char *input)
+{
+	int i, val;
+	const char *pos = input;
+	char *buf = (typeof(buf)) guid;
+
+	if (*pos == '{')
+		pos++;
+	for (i = 0; *pos && i < 32; pos++) {
+		if (*pos == '-') {
+			if (pos == input)
+				return -1;
+			continue;
+		}
+		if (*pos >= '0' && *pos <= '9')
+			val = *pos - '0';
+		else if (*pos >= 'a' && *pos <= 'f')
+			val = *pos - 'W';
+		else if (*pos >= 'A' && *pos <= 'F')
+			val = *pos - '7';
+		else
+			return -1;
+		if (i % 2) {
+			buf[i / 2] += val;
+			i++;
+		} else {
+			buf[i / 2] = val << 4;
+			i++;
+		}
+	}
+	if (i < 32)
+		return -1;
+	if (*input == '{') {
+		if (*pos != '}')
+			return -1;
+		pos++;
+	}
+	if (*pos)
+		return -1;
+	guid->data1 = ntohl(guid->data1);
+	guid->data2 = ntohs(guid->data2);
+	guid->data3 = ntohs(guid->data3);
+	return 0;
+}
diff --git a/security/hone/hone_pcapng.h b/security/hone/hone_pcapng.h
new file mode 100644
index 0000000..2987831c
--- /dev/null
+++ b/security/hone/hone_pcapng.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ */
+
+#ifndef _PCAPNG_H
+#define _PCAPNG_H
+
+#include <linux/atomic.h>
+#include <linux/time.h>
+
+#define HONE_USER_HEAD (HONE_USER | 1)
+#define HONE_USER_TAIL (HONE_USER | 2)
+
+#define GUID_FMT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+#define GUID_TUPLE(G) (G)->data1, (G)->data2, (G)->data3, \
+		(G)->data4[0], (G)->data4[1], (G)->data4[2], (G)->data4[3], \
+		(G)->data4[4], (G)->data4[5], (G)->data4[6], (G)->data4[7]
+
+unsigned int format_as_pcapng(
+		const struct device_info *devinfo, const struct reader_info *info,
+		struct hone_event *event, char *buf, unsigned int buflen);
+int parse_guid(struct guid_struct *guid, const char *input);
+
+#endif /* _PCAPNG_H */
diff --git a/security/hone/hone_ringbuf.c b/security/hone/hone_ringbuf.c
new file mode 100644
index 0000000..14a38f8
--- /dev/null
+++ b/security/hone/hone_ringbuf.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ *
+ * Implementation of lock-free ring buffer.
+ */
+
+#include <linux/atomic.h>
+
+#include "hone_ringbuf.h"
+
+int ring_append(struct ring_buf *ring, void *elem)
+{
+	unsigned int back;
+
+	for (;;) {
+		back = ring_back(ring);
+		if (back - ring_front(ring) >= ring->length)
+			return -1;
+		if ((unsigned int)
+			atomic_cmpxchg(&ring->back, back, back + 1) == back)
+			break;
+	}
+	ring->data[back % ring->length] = elem;
+	return 0;
+}
+
+void *ring_pop(struct ring_buf *ring)
+{
+	void *elem, **slot;
+	unsigned int front;
+
+	for (;;) {
+		front = ring_front(ring);
+		if (front == ring_back(ring))
+			return NULL;
+		slot = ring->data + (front % ring->length);
+		elem = *slot;
+		if (!elem)
+			continue;
+		if (cmpxchg(slot, elem, NULL) == elem)
+			break;
+	}
+	atomic_inc(&ring->front);
+	return elem;
+}
diff --git a/security/hone/hone_ringbuf.h b/security/hone/hone_ringbuf.h
new file mode 100644
index 0000000..a12311c
--- /dev/null
+++ b/security/hone/hone_ringbuf.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ *
+ * Implementation of lock-free ring buffer.
+ */
+
+#ifndef _RINGBUF_H
+#define _RINGBUF_H
+
+#include <linux/types.h>
+
+struct ring_buf {
+	atomic_t front;
+	atomic_t back;
+	unsigned int length;
+	unsigned int pageorder;
+	void **data;
+};
+
+#define ring_front(ring) ((unsigned int) atomic_read(&(ring)->front))
+#define ring_back(ring) ((unsigned int) atomic_read(&(ring)->back))
+#define ring_used(ring) (ring_back(ring) - ring_front(ring))
+#define ring_is_empty(ring) (ring_front(ring) == ring_back(ring))
+
+int ring_append(struct ring_buf *ring, void *elem);
+void *ring_pop(struct ring_buf *ring);
+
+#endif /* _RINGBUF_H */
diff --git a/security/hone/hone_socket_lookup.c b/security/hone/hone_socket_lookup.c
new file mode 100644
index 0000000..6b0f355
--- /dev/null
+++ b/security/hone/hone_socket_lookup.c
@@ -0,0 +1,264 @@
+/*
+ * Modifications copyright (C) 2011 Battelle Memorial Institute
+ *
+ * Licensed under the GNU General Public License Version 2.
+ * See LICENSE for the full text of the license.
+ * See DISCLAIMER for additional disclaimers.
+ *
+ * Author: Brandon Carpenter
+ */
+
+/*
+ * The following code was conveniently borrowed form the xt_socket
+ * iptables module and used with minor modifications.  Thanks guys!
+ *
+ * Transparent proxy support for Linux/iptables
+ *
+ * Copyright (C) 2007-2008 BalaBit IT Ltd.
+ * Author: Krisztian Kovacs
+ */
+
+#include <linux/version.h>
+#include <linux/skbuff.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/icmp.h>
+#include <net/sock.h>
+#include <net/inet_sock.h>
+
+#include "hone.h"
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#include <net/ipv6.h>
+#include <net/inet6_hashtables.h>
+#endif
+
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+#define XT_SOCKET_HAVE_CONNTRACK 1
+#include <net/netfilter/nf_conntrack.h>
+#endif
+
+static int extract_icmp4_fields(const struct sk_buff *skb, u8 *protocol,
+		__be32 *raddr, __be32 *laddr, __be16 *rport, __be16 *lport)
+{
+	unsigned int outside_hdrlen = ip_hdrlen(skb);
+	struct iphdr *inside_iph, _inside_iph;
+	struct icmphdr *icmph, _icmph;
+	__be16 *ports, _ports[2];
+
+	icmph = skb_header_pointer(skb, outside_hdrlen,
+				   sizeof(_icmph), &_icmph);
+	if (icmph == NULL)
+		return 1;
+
+	switch (icmph->type) {
+	case ICMP_DEST_UNREACH:
+	case ICMP_SOURCE_QUENCH:
+	case ICMP_REDIRECT:
+	case ICMP_TIME_EXCEEDED:
+	case ICMP_PARAMETERPROB:
+		break;
+	default:
+		return 1;
+	}
+
+	inside_iph = skb_header_pointer(skb, outside_hdrlen +
+					sizeof(struct icmphdr),
+					sizeof(_inside_iph), &_inside_iph);
+	if (inside_iph == NULL)
+		return 1;
+
+	if (inside_iph->protocol != IPPROTO_TCP &&
+	    inside_iph->protocol != IPPROTO_UDP)
+		return 1;
+
+	ports = skb_header_pointer(skb, outside_hdrlen +
+				   sizeof(struct icmphdr) +
+				   (inside_iph->ihl << 2),
+				   sizeof(_ports), &_ports);
+	if (ports == NULL)
+		return 1;
+
+	/* the inside IP packet is the one quoted from our side, thus
+	 * its saddr is the local address */
+	*protocol = inside_iph->protocol;
+	*laddr = inside_iph->saddr;
+	*lport = ports[0];
+	*raddr = inside_iph->daddr;
+	*rport = ports[1];
+
+	return 0;
+}
+
+struct sock *lookup_v4_sock(const struct sk_buff *skb,
+		const struct net_device *indev)
+{
+	struct iphdr *iph = ip_hdr(skb);
+	struct sock *sk;
+	__be32 daddr = 0, saddr = 0;
+	__be16 dport = 0, sport = 0;
+	u8 protocol = 0;
+
+	if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
+		struct udphdr _hdr, *hp;
+
+		hp = skb_header_pointer(skb, ip_hdrlen(skb),
+					sizeof(_hdr), &_hdr);
+		if (!hp)
+			return NULL;
+
+		protocol = iph->protocol;
+		saddr = iph->saddr;
+		sport = hp->source;
+		daddr = iph->daddr;
+		dport = hp->dest;
+
+	} else if (iph->protocol == IPPROTO_ICMP) {
+		if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr,
+					&sport, &dport))
+			return NULL;
+	} else {
+		return NULL;
+	}
+
+#ifdef XT_SOCKET_HAVE_CONNTRACK
+	/* Do the lookup with the original socket address in case this is a
+	 * reply packet of an established SNAT-ted connection. */
+	{
+		enum ip_conntrack_info ctinfo;
+		struct nf_conn const *ct = nf_ct_get(skb, &ctinfo);
+
+		if (ct && !nf_ct_is_untracked(ct) &&
+			((iph->protocol != IPPROTO_ICMP &&
+				ctinfo == IP_CT_IS_REPLY + IP_CT_ESTABLISHED) ||
+				(iph->protocol == IPPROTO_ICMP &&
+					ctinfo == IP_CT_IS_REPLY + IP_CT_RELATED)) &&
+			(ct->status & IPS_SRC_NAT_DONE)) {
+
+			daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
+			dport = (iph->protocol == IPPROTO_TCP) ?
+				ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port :
+				ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
+		}
+	}
+#endif
+
+	if (protocol == IPPROTO_TCP)
+		sk = __inet_lookup(dev_net(skb->dev), &tcp_hashinfo,
+				saddr, sport, daddr, dport, indev->ifindex);
+	else
+		sk = udp4_lib_lookup(dev_net(skb->dev),
+				saddr, sport, daddr, dport, indev->ifindex);
+	if (!sk)
+		return NULL;
+
+	/* Ignore sockets listening on INADDR_ANY */
+	if (sk->sk_state != TCP_TIME_WAIT && inet_sk(sk)->inet_rcv_saddr == 0) {
+		put_sock(sk);
+		return NULL;
+	}
+	return sk;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int extract_icmp6_fields(const struct sk_buff *skb,
+				unsigned int outside_hdrlen, int *protocol,
+				struct in6_addr **raddr,
+				struct in6_addr **laddr, __be16 *rport,
+				__be16 *lport)
+{
+	struct ipv6hdr *inside_iph, _inside_iph;
+	struct icmp6hdr *icmph, _icmph;
+	__be16 *ports, _ports[2], _ignore;
+	u8 inside_nexthdr;
+	int inside_hdrlen;
+
+	icmph = skb_header_pointer(skb, outside_hdrlen, sizeof(_icmph),
+				&_icmph);
+	if (!icmph)
+		return 1;
+	if (icmph->icmp6_type & ICMPV6_INFOMSG_MASK)
+		return 1;
+
+	inside_iph = skb_header_pointer(
+		skb, outside_hdrlen + sizeof(_icmph), sizeof(_inside_iph),
+		&_inside_iph);
+	if (!inside_iph)
+		return 1;
+
+	inside_nexthdr = inside_iph->nexthdr;
+	inside_hdrlen = ipv6_skip_exthdr(
+		skb, outside_hdrlen + sizeof(_icmph) + sizeof(_inside_iph),
+		&inside_nexthdr, &_ignore);
+	if (inside_hdrlen < 0)
+		/* hjm: Packet has no/incomplete transport layer headers. */
+		return 1;
+	if (inside_nexthdr != IPPROTO_TCP && inside_nexthdr != IPPROTO_UDP)
+		return 1;
+
+	ports = skb_header_pointer(skb, inside_hdrlen, sizeof(_ports), &_ports);
+	if (!ports)
+		return 1;
+
+	/* the inside IP packet is the one quoted from our side, thus
+	 * its saddr is the local address */
+	*protocol = inside_nexthdr;
+	*laddr = &inside_iph->saddr;
+	*lport = ports[0];
+	*raddr = &inside_iph->daddr;
+	*rport = ports[1];
+
+	return 0;
+}
+
+struct sock *lookup_v6_sock(const struct sk_buff *skb,
+			const struct net_device *indev)
+{
+	struct sock *sk;
+	struct in6_addr *daddr, *saddr;
+	__be16 dport, sport;
+	int thoff = 0, tproto;
+
+	tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
+	if (tproto < 0)
+		/* unable to find transport header in IPv6 packet */
+		return NULL;
+
+	if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
+		struct udphdr _hdr, *hp;
+		struct ipv6hdr *iph;
+
+		hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
+		if (!hp)
+			return NULL;
+
+		iph = ipv6_hdr(skb);
+		saddr = &iph->saddr;
+		sport = hp->source;
+		daddr = &iph->daddr;
+		dport = hp->dest;
+	} else if (tproto == IPPROTO_ICMPV6) {
+		if (extract_icmp6_fields(skb, thoff, &tproto,
+					&saddr, &daddr, &sport, &dport))
+			return NULL;
+	} else {
+		return NULL;
+	}
+
+	if (tproto == IPPROTO_TCP)
+		sk = inet6_lookup(dev_net(skb->dev), &tcp_hashinfo,
+				saddr, sport, daddr, dport, indev->ifindex);
+	else
+		sk = __udp6_lib_lookup(dev_net(skb->dev),
+				saddr, sport, daddr, dport, indev->ifindex,
+				&udp_table);
+
+	/* Ignore sockets listening on INADDR_ANY */
+	if (sk && sk->sk_state != TCP_TIME_WAIT && !inet_sk(sk)->inet_rcv_saddr) {
+		put_sock(sk);
+		return NULL;
+	}
+	/* TODO(pmoody): add pid information here. */
+	return sk;
+}
+#endif
-- 
2.0.0.526.g5318336


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-01  1:21 [PATCH v2 0/2] RFC, aiding pid/network correlation Peter Moody
  2014-08-01  1:21 ` [PATCH 1/2] security: create task_post_create callback Peter Moody
  2014-08-01  1:21 ` [PATCH 2/2] security: Hone LSM Peter Moody
@ 2014-08-01 12:16 ` Samir Bellabes
  2014-08-01 17:22   ` Peter Moody
  2 siblings, 1 reply; 19+ messages in thread
From: Samir Bellabes @ 2014-08-01 12:16 UTC (permalink / raw)
  To: Peter Moody; +Cc: linux-security-module, brandon.carpenter, casey, netdev

Peter Moody <pmoody@google.com> writes:

> I'm interested in having a host-based monitoring mechanism in
> place in the linux kernel. At this point I'm specifically looking
> to tie any given packet seen on the network back to the process
> that sent or received it. This is the sort of information our
> incident responders are constantly asking for.
>
> This is round 2 of the patchset. It's essentially taking HONE [1],
> a kernel module originally written by Brandon Carpenter and switches
> the hooks to use the standard (plus a new one, task_post_create) LSM
> hooks + a run through cleanfile/checkpatch.
>
> At a high level, Hone hooks process/socket creations/terminations
> and inet/inet6 packets that are sent or received. A userspace
> application can then correlate packet to process by reading the
> events from the kernel.
>
> (Note, there doesn't appear to be outbound version of the callback
> socket_sock_rcv_skb and the socket_sendmsg/socket_recvmsg
> are called too early in the process to be used so this uses netfilter
> hooks.)
>
> This patchset makes the events available as text via securityfs
> in /sys/kernel/security/hone/text and /sys/kernel/security/hone/pcapng.
> The text output looks like
>
> 3.350826817 EXEC 718 1 0 0 "/usr/sbin/cupsd" /usr/sbin/cupsd -f
> 3.350826817 SOCK O 718 1 0 0 b14e0000
> ...
> 5301.871561546 EXEC 2652 2586 1000 1000 "/bin/less" less
> 5303.104510870 EXEC 2653 2651 0 0 "/bin/cat" cat /sys/kernel/security/hone/text
> 5303.110322648 PAKT O 382d0700 2524 TCPv4 169.254.0.11:22 -> 169.254.0.2:49387 120
>
> and the pcapng format is described in hone_pcapng.h.
>
> There are some drawbacks with this method. Notably, it doesn't
> accurately track the owning pid of sockets passed via dup(), dup2()
> etc.
>
> This particular approach is all very experimental. We had a need
> for this level of monitoring on some of our machines (did I mention
> the incident responders?) and HONE had the best features/efficiency.
>
> I've CC'd the netdev folks at James' suggestion. I CC'd you, Casey
> as you were the one who suggested this be a proper LSM.
>
> So I'm humbly requesting comments.
>
>  * Is there a better (more efficient/extensible) way to do this?
>  * Is there already an existing mechanism to do this?

Hi Peter,
I have built a such subsystem, for years now.
Please, you can access latest public patchset here :

https://lkml.org/lkml/2011/5/5/132

monitoring events is possible with snet.

thanks,

(resending, first mail didn't hit lists)

>  * Is there any interest in something like this living in the
>    kernel? Or is the dkms distributed path the way to go?
>
> And if this is all reasonable, is it possible to add a
> socket_sock_send_skb callback and where might that go?
>
> Finally, the linux-sensor project was released under the GPL but
> I'm not sure if there are any copyright issues ... ? I've just
> kept the copyright comments in any event.
>
> This has been tested against security-next
>
> [1] https://github.com/HoneProject/Linux-Sensor
>
> Peter Moody (2):
>   security: create task_post_create callback.
>   security: Hone LSM
>
>  include/linux/hone.h               |  50 +++
>  include/linux/security.h           |   8 +
>  kernel/fork.c                      |   1 +
>  security/Kconfig                   |   1 +
>  security/Makefile                  |   2 +
>  security/capability.c              |   5 +
>  security/hone/Kconfig              |   8 +
>  security/hone/Makefile             |   3 +
>  security/hone/hone.h               | 164 ++++++++++
>  security/hone/hone_event.c         | 625 +++++++++++++++++++++++++++++++++++++
>  security/hone/hone_lsm.c           | 183 +++++++++++
>  security/hone/hone_mmutil.c        | 106 +++++++
>  security/hone/hone_mmutil.h        |  20 ++
>  security/hone/hone_notify.c        | 450 ++++++++++++++++++++++++++
>  security/hone/hone_pcapng.c        | 596 +++++++++++++++++++++++++++++++++++
>  security/hone/hone_pcapng.h        |  30 ++
>  security/hone/hone_ringbuf.c       |  51 +++
>  security/hone/hone_ringbuf.h       |  34 ++
>  security/hone/hone_socket_lookup.c | 264 ++++++++++++++++
>  security/security.c                |   5 +
>  20 files changed, 2606 insertions(+)
>  create mode 100644 include/linux/hone.h
>  create mode 100644 security/hone/Kconfig
>  create mode 100644 security/hone/Makefile
>  create mode 100644 security/hone/hone.h
>  create mode 100644 security/hone/hone_event.c
>  create mode 100644 security/hone/hone_lsm.c
>  create mode 100644 security/hone/hone_mmutil.c
>  create mode 100644 security/hone/hone_mmutil.h
>  create mode 100644 security/hone/hone_notify.c
>  create mode 100644 security/hone/hone_pcapng.c
>  create mode 100644 security/hone/hone_pcapng.h
>  create mode 100644 security/hone/hone_ringbuf.c
>  create mode 100644 security/hone/hone_ringbuf.h
>  create mode 100644 security/hone/hone_socket_lookup.c
>
> -- 
> 2.0.0.526.g5318336
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-01 12:16 ` [PATCH v2 0/2] RFC, aiding pid/network correlation Samir Bellabes
@ 2014-08-01 17:22   ` Peter Moody
  2014-08-02  0:30     ` Samir Bellabes
  2014-08-02  4:55     ` Alex Elsayed
  0 siblings, 2 replies; 19+ messages in thread
From: Peter Moody @ 2014-08-01 17:22 UTC (permalink / raw)
  To: Samir Bellabes; +Cc: linux-security-module, brandon.carpenter, casey, netdev


Hi Samir,

>>  * Is there already an existing mechanism to do this?
>
> Hi Peter,
> I have built a such subsystem, for years now.
> Please, you can access latest public patchset here :
>
> https://lkml.org/lkml/2011/5/5/132

Interesting, thanks! I hadn't know about snet.

The patches don't apply cleanly, and while the merge wasn't difficult,
it looks like the code has gotten out of sync with mainline and doesn't
build (at least when applied to security-next). Did anything ever happen
with snet?

>From looking at the code, it looks kind of like a 'little-snitch' for
linux, is that right? A process tries to open a socket/etc and snet
requests that the user accept/reject the connection, and presumably
while the user is being queried one could dig through /proc to find the
exe/cmdline of the process making the request.

One thing that Hone does which snet doesn't seem to do (apologies if
this is incorrect but I can't test) is that it provides a full process
tree for a given pid back to init. When doing an investigation into a
system compromise, knowing what started the process making the
suspicious connection(s) (and what started *that* process) is often just
as important as knowing that there's a compromise to begin with.

Cheers,

> monitoring events is possible with snet.
>
> thanks,
>
> (resending, first mail didn't hit lists)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-01 17:22   ` Peter Moody
@ 2014-08-02  0:30     ` Samir Bellabes
  2014-08-02 15:05       ` Peter Moody
  2014-08-02  4:55     ` Alex Elsayed
  1 sibling, 1 reply; 19+ messages in thread
From: Samir Bellabes @ 2014-08-02  0:30 UTC (permalink / raw)
  To: Peter Moody; +Cc: linux-security-module, brandon.carpenter, casey, netdev

Peter Moody <pmoody@google.com> writes:

> Hi Samir,
>
>>>  * Is there already an existing mechanism to do this?
>>
>> Hi Peter,
>> I have built a such subsystem, for years now.
>> Please, you can access latest public patchset here :
>>
>> https://lkml.org/lkml/2011/5/5/132
>
> Interesting, thanks! I hadn't know about snet.

Peter,

After taking a look at your patchset, I understand that you want to make
a link between network packets and applications, by keeping
system-related informations inside a memory structure (this process
tree).

I started snet because of this. Packet filtering is not enough
powerfull to be "easily" used by users. By "users", it includes network
specialists too, because of this missing link to informations related to
"system" (pid, process, memory, syscall, etc), and not only "network"
related (procotol, port, etc.)

I think indeed that LSM hooks are the perfect place to understand the
behavior of applications.

> The patches don't apply cleanly, and while the merge wasn't difficult,
> it looks like the code has gotten out of sync with mainline and doesn't
> build (at least when applied to security-next). Did anything ever happen
> with snet?

sure, this public release is out of sync with current kernels (it's 3
years old). I can release a up to date patchset.

> From looking at the code, it looks kind of like a 'little-snitch' for
> linux, is that right?

Indeed, snet is including this kind of "control application", which is
missing to the linux world, as packet filter is the "only way" to go.

Main goal is to build a framework for having a kind of "LSM userspace
subsystem", pushing the decision to userspace, and to other related OS
in the network. 

Why this ?
- LSM are monolithic : applying a system policy on one isolated OS is
no more valuable with our connected world.
- network filtering tools are not system related : what is more easiest
than this network related analysis : "ok, so that's chromium which is
connecting to .." ? But this sentence is only build this system related
information (process, syscall "connect"), not on some "packet
inspection".
- build new kind of security models, not only related to a isolated OS,
but seeing the network as a global system. We are only sharing policy
between hosts.. which is pretty inefficent nowsdays.

>A process tries to open a socket/etc and snet
> requests that the user accept/reject the connection,

indeed, this is one of the possible application of snet.
but by "user", it's not only the physical user. It may be a process from
userspace, or a decision from a central server in the network. So to
fully agree on this, I may say : "snet requets userspace to
accept/reject the connection". Decision comes from user in real time
(click) or a security process built on a (local or distributed) formal
model.

> and presumably
> while the user is being queried one could dig through /proc to find the
> exe/cmdline of the process making the request.

we don't have dig /proc, and I think it's a bad idea.
In fact, we don't need it at all.
Indeed, LSM hooks are occuring in the process context, so at the time of
the syscall, system information is related to the application.

So, pid information is already part of the message sent
from kernel subsystem to userspace. see snet_nl_send_event()
exe/cmdline is in the same way sent from snet kernel subsystem (but it
wasn't in the 2011 patches series)

but I think you get it right on the fact that extracting information
*related* to the syscall is the most valuable part.

In the same time, current behavior is to put the process to a wait
queue, until a verdict from userspace is coming back. (process context
allow to sleep here)

a look at "genetlink attributes" in snet.h will give you access to all
possible kind of available informations (at the time of this patch 3
years ago, now the list is more powerfull, and not only related to
network) 

> One thing that Hone does which snet doesn't seem to do (apologies if
> this is incorrect but I can't test) is that it provides a full process
> tree for a given pid back to init.

snet is more like a framework now.
you can interactively register which syscall you want to monitor.
then kernel substem will sent you informations.
unregister, and the kernel subsystem is going quiet.

in order to build your process tree, you just use the userspace lib (I
don't think it is yet publicly available, I have to put this up-to-date
too) 

the lib is build on the same libpcap callback mecanism : you register a
syscall with a callback function. your callback function is called to
manage the informations every time the related syscall occured.
Here you can build your process tree, or do whatever you want. 

Now, kernel subsystem doesn't required always a userspace verdict, as
there is a "monitor mode", which is exactly what you will use if you
decide to use snet.

As I said, snet is more like a framework to push this valuable
informations to userspace, do whatever you want, and send back your
policy decision (if it needs one) 

> When doing an investigation into a
> system compromise, knowing what started the process making the
> suspicious connection(s) (and what started *that* process) is often just
> as important as knowing that there's a compromise to begin with.

this is exaclty one exemple of informations which is truly valuable by
users or admins, and not direcly/interactively available on ours systems.

for me, best way to do that is building a simple and generic framework
which will help you/admins/users to build simple scenarios from
userspace to get what you want. 

> Cheers,

Peter, thank you for pushing this discussion on the list, I think this
kind of usability is missing, now for years, from our systems.

cheers,

sam

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-01 17:22   ` Peter Moody
  2014-08-02  0:30     ` Samir Bellabes
@ 2014-08-02  4:55     ` Alex Elsayed
  2014-08-03  1:34       ` Peter Moody
  1 sibling, 1 reply; 19+ messages in thread
From: Alex Elsayed @ 2014-08-02  4:55 UTC (permalink / raw)
  To: linux-security-module; +Cc: netdev

Peter Moody wrote:

<snip>
> One thing that Hone does which snet doesn't seem to do (apologies if
> this is incorrect but I can't test) is that it provides a full process
> tree for a given pid back to init. When doing an investigation into a
> system compromise, knowing what started the process making the
> suspicious connection(s) (and what started *that* process) is often just
> as important as knowing that there's a compromise to begin with.

Out of curiosity, have you looked at Tomoyo much at all? In particular, it:

1.) Keeps a tree all the way back to init
2.) Has network event hooks (see footnote [1])
3.) Has an interactive API for managing policy violations (tomoyo-queryd[2] 
uses it)
4.) Is in mainline already.

The combination is actually sufficient to implement what you want for Hone 
_today_ as far as I can tell, and there's even the out-of-tree AKARI variant 
if you want to use it together with another LSM.

There's also Caitsith[3] (also from Tetsuo Handa), which might be even 
better suited but is not in mainline yet.

[1] It has these hooks for inet sockets, and similar for unix:
network inet stream bind $ADDRESS $PORT
network inet stream listen $ADDRESS $PORT
network inet stream connect $ADDRESS $PORT
network inet dgram bind $ADDRESS $PORT
network inet dgram send $ADDRESS $PORT
network inet raw bind $ADDRESS $PROTOCOL
network inet raw send $ADDRESS $PROTOCOL

See http://tomoyo.sourceforge.jp/2.5/policy-specification/domain-policy-syntax.html.en#network_inet

[2] http://tomoyo.sourceforge.jp/2.5/man-pages/tomoyo-queryd.html.en
[3] http://caitsith.sourceforge.jp/


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-02  0:30     ` Samir Bellabes
@ 2014-08-02 15:05       ` Peter Moody
  0 siblings, 0 replies; 19+ messages in thread
From: Peter Moody @ 2014-08-02 15:05 UTC (permalink / raw)
  To: Samir Bellabes; +Cc: linux-security-module, brandon.carpenter, casey, netdev


Hi Sam

> snet is more like a framework now.
> you can interactively register which syscall you want to monitor.
> then kernel substem will sent you informations.
> unregister, and the kernel subsystem is going quiet.
>
> in order to build your process tree, you just use the userspace lib (I
> don't think it is yet publicly available, I have to put this up-to-date
> too) 
>
> the lib is build on the same libpcap callback mecanism : you register a
> syscall with a callback function. your callback function is called to
> manage the informations every time the related syscall occured.
> Here you can build your process tree, or do whatever you want. 
>
> Now, kernel subsystem doesn't required always a userspace verdict, as
> there is a "monitor mode", which is exactly what you will use if you
> decide to use snet.
>
> As I said, snet is more like a framework to push this valuable
> informations to userspace, do whatever you want, and send back your
> policy decision (if it needs one) 

It sounds at least in theory like snet can do what I'm looking for. I
have a few concerns however:

 * since I'm trying to tie individual packets to processes, I think that
   would mean that I'd have to register for socket_sendmsg/socket_recvmsg.
   Would that mean a trip to userspace (for the bpf callback at least if
   this is just in monitor mode) for every packet?

 * obviously the current lsm hooks/attributes from snet.h don't account
   for tracking processes.

In any event, I'm interested in seeing the updated patchset/userspace
lib for registering/reading events.

Cheers

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-02  4:55     ` Alex Elsayed
@ 2014-08-03  1:34       ` Peter Moody
  2014-08-03  1:49         ` Alex Elsayed
  0 siblings, 1 reply; 19+ messages in thread
From: Peter Moody @ 2014-08-03  1:34 UTC (permalink / raw)
  To: Alex Elsayed; +Cc: linux-security-module, netdev


Hey Alex,

On Fri, Aug 01 2014 at 21:55, Alex Elsayed wrote:
> Out of curiosity, have you looked at Tomoyo much at all? In particular, it:
>
> 1.) Keeps a tree all the way back to init
> 2.) Has network event hooks (see footnote [1])
> 3.) Has an interactive API for managing policy violations (tomoyo-queryd[2] 
> uses it)
> 4.) Is in mainline already.

I have looked at tomoyo before. There were a couple of things that kept
it from being suitable for our needs:

The big one is that since the process tree is used to check policy, it's
kept in-kernel and I'm primarily interested in having these events be
easily exportable.  IIRC (at least when I last looked), it wasn't
possible to stream the events as they happened. tomoyo-queryd looks like
it gets me real-time policy violations, but I don't have any policy
per-se. I'm just trying to monitor processes and network activity.

We also already use apparmor so switching to a different LSM was a
non-trivial task (admittedly this is now an issue for hone too, but hone
wasn't an LSM initially).

> The combination is actually sufficient to implement what you want for Hone 
> _today_ as far as I can tell, and there's even the out-of-tree AKARI variant 
> if you want to use it together with another LSM.
>
> There's also Caitsith[3] (also from Tetsuo Handa), which might be even 
> better suited but is not in mainline yet.

I'm not familiar with AKARI or Caitsith. I'll take a look.

 Cheers,
 peter

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-03  1:34       ` Peter Moody
@ 2014-08-03  1:49         ` Alex Elsayed
  2014-08-03  2:19           ` Peter Moody
  0 siblings, 1 reply; 19+ messages in thread
From: Alex Elsayed @ 2014-08-03  1:49 UTC (permalink / raw)
  To: linux-security-module; +Cc: netdev

Peter Moody wrote:

> 
> Hey Alex,
> 
> On Fri, Aug 01 2014 at 21:55, Alex Elsayed wrote:
>> Out of curiosity, have you looked at Tomoyo much at all? In particular,
>> it:
>>
>> 1.) Keeps a tree all the way back to init
>> 2.) Has network event hooks (see footnote [1])
>> 3.) Has an interactive API for managing policy violations
>> (tomoyo-queryd[2] uses it)
>> 4.) Is in mainline already.
> 
> I have looked at tomoyo before. There were a couple of things that kept
> it from being suitable for our needs:
> 
> The big one is that since the process tree is used to check policy, it's
> kept in-kernel and I'm primarily interested in having these events be
> easily exportable.  IIRC (at least when I last looked), it wasn't
> possible to stream the events as they happened. tomoyo-queryd looks like
> it gets me real-time policy violations, but I don't have any policy
> per-se. I'm just trying to monitor processes and network activity.

Well, the simple answer is "define a policy that allows everything except 
network operations, and denies those" - this is reasonably simple if you use 
ACL groups because you can set the 'default policy' with acl group 0.

> We also already use apparmor so switching to a different LSM was a
> non-trivial task (admittedly this is now an issue for hone too, but hone
> wasn't an LSM initially).

Yeah, there are flavors of Tomoyo (out-of-tree) that can be stacked, and 
there's the ongoing effort from Casey Schaufler to enable stacking more 
generally.

>> The combination is actually sufficient to implement what you want for
>> Hone _today_ as far as I can tell, and there's even the out-of-tree AKARI
>> variant if you want to use it together with another LSM.
>>
>> There's also Caitsith[3] (also from Tetsuo Handa), which might be even
>> better suited but is not in mainline yet.
> 
> I'm not familiar with AKARI or Caitsith. I'll take a look.

AKARI is basically just Tomoyo, but as a loadable kernel module and with 
(IIRC) stacking capability.

CaitSith is rather different, in that rather than having domain be the 
primary key things operate off of, the action is the central piece. So while 
Tomoyo's policy syntax is

DOMAIN
    POLICY ACTION CONDITION

CaitSith's is

ACTION [QUALIFIER]
    PRIORITY POLICY CONDITION [CONDITION...]

That's why I thought it might be a better fit - it'd allow you to specify 
_exactly_ the actions (socket connect, etc) you care about.

>  Cheers,
>  peter
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in the body of a message to
> majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-03  1:49         ` Alex Elsayed
@ 2014-08-03  2:19           ` Peter Moody
  2014-08-03  2:28             ` Alex Elsayed
  0 siblings, 1 reply; 19+ messages in thread
From: Peter Moody @ 2014-08-03  2:19 UTC (permalink / raw)
  To: Alex Elsayed; +Cc: linux-security-module, netdev


On Sat, Aug 02 2014 at 18:49, Alex Elsayed wrote:

> Well, the simple answer is "define a policy that allows everything except 
> network operations, and denies those" - this is reasonably simple if you use 
> ACL groups because you can set the 'default policy' with acl group 0.

I'm not understanding. I don't want to deny network operations, I just
want to be able to associate the operation with the 'offending' process.

> Yeah, there are flavors of Tomoyo (out-of-tree) that can be stacked, and 
> there's the ongoing effort from Casey Schaufler to enable stacking more 
> generally.

Yeah, Casey was the one who suggested that I re-write this as an LSM. I
think he saw the monitoring that I'm trying to do (as opposed to
standard LSM deny/permit) as a good candidate for stacking.


> CaitSith is rather different, in that rather than having domain be the 
> primary key things operate off of, the action is the central piece. So while 
> Tomoyo's policy syntax is
>
> DOMAIN
>     POLICY ACTION CONDITION
>
> CaitSith's is
>
> ACTION [QUALIFIER]
>     PRIORITY POLICY CONDITION [CONDITION...]

Interesting. It sounds like it's still primary designed to deny/permit
actions (based on some policy) and I'm really just looking to monitor.

 Cheers,
 peter

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-03  2:19           ` Peter Moody
@ 2014-08-03  2:28             ` Alex Elsayed
  2014-08-03  2:38               ` Peter Moody
  0 siblings, 1 reply; 19+ messages in thread
From: Alex Elsayed @ 2014-08-03  2:28 UTC (permalink / raw)
  To: linux-security-module; +Cc: netdev

Peter Moody wrote:

> 
> On Sat, Aug 02 2014 at 18:49, Alex Elsayed wrote:
> 
>> Well, the simple answer is "define a policy that allows everything except
>> network operations, and denies those" - this is reasonably simple if you
>> use ACL groups because you can set the 'default policy' with acl group 0.
> 
> I'm not understanding. I don't want to deny network operations, I just
> want to be able to associate the operation with the 'offending' process.
> 
>> Yeah, there are flavors of Tomoyo (out-of-tree) that can be stacked, and
>> there's the ongoing effort from Casey Schaufler to enable stacking more
>> generally.
> 
> Yeah, Casey was the one who suggested that I re-write this as an LSM. I
> think he saw the monitoring that I'm trying to do (as opposed to
> standard LSM deny/permit) as a good candidate for stacking.
> 
> 
>> CaitSith is rather different, in that rather than having domain be the
>> primary key things operate off of, the action is the central piece. So
>> while Tomoyo's policy syntax is
>>
>> DOMAIN
>>     POLICY ACTION CONDITION
>>
>> CaitSith's is
>>
>> ACTION [QUALIFIER]
>>     PRIORITY POLICY CONDITION [CONDITION...]
> 
> Interesting. It sounds like it's still primary designed to deny/permit
> actions (based on some policy) and I'm really just looking to monitor.

Oh, I see now. Okay, that's actually considerably simpler - I just had 
somehow gotten it fixated into my mind that the info would be used to decide 
on allow/deny actions.

The trick to do what you want is the 'audit' support in both - 
here I'll use CaitSith as an example since the syntax is nicer.

In the header of a CaitSith policy, you specify resource limits for audit 
logs in the format

quota audit[$audit_index] allowed=$max_logs_for_allowed_request 
unmatched=$max_logs_for_unmatched_request 
denied=$max_logs_for_denied_request

(sans the linewrapping)

Now, by default _everything_ logs into audit index zero, but you can have 
multiple audit logs, and you can specify which one an action logs into. The 
result:

# Don't pollute the logs
quota audit[0] allowed=0 unmatched=0 denied=0

# Allow a one-million-item backlog of events that don't
# have an explicit policy allow/deny set on this unusual audit field
quota audit[1] allowed=0 unmatched=1000000 denied=0

# Whenever someone tries to bind an AF_UNIX socket...
0 acl unix_stream_bind
    # ...log that sucker.
    audit 1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-03  2:28             ` Alex Elsayed
@ 2014-08-03  2:38               ` Peter Moody
  2014-08-03  2:41                 ` Alex Elsayed
  0 siblings, 1 reply; 19+ messages in thread
From: Peter Moody @ 2014-08-03  2:38 UTC (permalink / raw)
  To: Alex Elsayed; +Cc: linux-security-module, netdev


On Sat, Aug 02 2014 at 19:28, Alex Elsayed wrote:

> Oh, I see now. Okay, that's actually considerably simpler - I just had 
> somehow gotten it fixated into my mind that the info would be used to decide 
> on allow/deny actions.
>
> The trick to do what you want is the 'audit' support in both - 
> here I'll use CaitSith as an example since the syntax is nicer.

Do these audit logs end up with the audit subsystem? My experience with
the audit subsystem is that performance takes a big hit when you start
sending thousands (or even hundreds) of audit messages per second.

> In the header of a CaitSith policy, you specify resource limits for audit 
> logs in the format

I will definitely check out caitsith though. I think I saw Tetsuo talk
about it at LSS in San Diego a few years ago.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-03  2:38               ` Peter Moody
@ 2014-08-03  2:41                 ` Alex Elsayed
  2014-08-03  2:47                   ` Alex Elsayed
  0 siblings, 1 reply; 19+ messages in thread
From: Alex Elsayed @ 2014-08-03  2:41 UTC (permalink / raw)
  To: linux-security-module; +Cc: netdev

Peter Moody wrote:

> 
> On Sat, Aug 02 2014 at 19:28, Alex Elsayed wrote:
> 
>> Oh, I see now. Okay, that's actually considerably simpler - I just had
>> somehow gotten it fixated into my mind that the info would be used to
>> decide on allow/deny actions.
>>
>> The trick to do what you want is the 'audit' support in both -
>> here I'll use CaitSith as an example since the syntax is nicer.
> 
> Do these audit logs end up with the audit subsystem? My experience with
> the audit subsystem is that performance takes a big hit when you start
> sending thousands (or even hundreds) of audit messages per second.

No, they go straight to /proc/caitsith/audit and wind up looking like this:

#2012/04/08 05:03:03# global-pid=3720 result=allowed priority=100 / read 
path="/tmp/file1" task.pid=3720 task.ppid=3653 task.uid=0 task.gid=0 
task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 
task.type!=execute_handler task.exe="/bin/cat" task.domain="/usr/sbin/sshd" 
path.uid=0 path.gid=0 path.ino=2113451 path.major=8 path.minor=1 
path.perm=0644 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 
path.parent.gid=0 path.parent.ino=2097153 path.parent.major=8 
path.parent.minor=1 path.parent.perm=01777 path.parent.type=directory 
path.parent.fsmagic=0xEF53

>> In the header of a CaitSith policy, you specify resource limits for audit
>> logs in the format
> 
> I will definitely check out caitsith though. I think I saw Tetsuo talk
> about it at LSS in San Diego a few years ago.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-03  2:41                 ` Alex Elsayed
@ 2014-08-03  2:47                   ` Alex Elsayed
  2014-08-03  3:14                     ` Peter Moody
  0 siblings, 1 reply; 19+ messages in thread
From: Alex Elsayed @ 2014-08-03  2:47 UTC (permalink / raw)
  To: linux-security-module; +Cc: netdev

Alex Elsayed wrote:

> Peter Moody wrote:
> 
>> 
>> On Sat, Aug 02 2014 at 19:28, Alex Elsayed wrote:
>> 
>>> Oh, I see now. Okay, that's actually considerably simpler - I just had
>>> somehow gotten it fixated into my mind that the info would be used to
>>> decide on allow/deny actions.
>>>
>>> The trick to do what you want is the 'audit' support in both -
>>> here I'll use CaitSith as an example since the syntax is nicer.
>> 
>> Do these audit logs end up with the audit subsystem? My experience with
>> the audit subsystem is that performance takes a big hit when you start
>> sending thousands (or even hundreds) of audit messages per second.
> 
> No, they go straight to /proc/caitsith/audit and wind up looking like
> this:
> 
> #2012/04/08 05:03:03# global-pid=3720 result=allowed priority=100 / read
> path="/tmp/file1" task.pid=3720 task.ppid=3653 task.uid=0 task.gid=0
> task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0
> task.type!=execute_handler task.exe="/bin/cat"
> task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451
> path.major=8 path.minor=1 path.perm=0644 path.type=file
> path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0
> path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1
> path.parent.perm=01777 path.parent.type=directory
> path.parent.fsmagic=0xEF53

Actually, now that I look at that, you'd need to audit 'domain transition' 
events too - since that contains all the relevant PIDs, then the most recent 
domain transition with all of the right PIDs is sufficient to rebuild the 
tree back to init (recursively)


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-03  2:47                   ` Alex Elsayed
@ 2014-08-03  3:14                     ` Peter Moody
  2014-08-03  3:41                       ` Alex Elsayed
  0 siblings, 1 reply; 19+ messages in thread
From: Peter Moody @ 2014-08-03  3:14 UTC (permalink / raw)
  To: Alex Elsayed; +Cc: linux-security-module, netdev


On Sat, Aug 02 2014 at 19:47, Alex Elsayed wrote:
>> #2012/04/08 05:03:03# global-pid=3720 result=allowed priority=100 / read
>> path="/tmp/file1" task.pid=3720 task.ppid=3653 task.uid=0 task.gid=0
>> task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0
>> task.type!=execute_handler task.exe="/bin/cat"
>> task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451
>> path.major=8 path.minor=1 path.perm=0644 path.type=file
>> path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0
>> path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1
>> path.parent.perm=01777 path.parent.type=directory
>> path.parent.fsmagic=0xEF53
>
> Actually, now that I look at that, you'd need to audit 'domain transition' 
> events too - since that contains all the relevant PIDs, then the most recent 
> domain transition with all of the right PIDs is sufficient to rebuild the 
> tree back to init (recursively)

How are network events logged? The documentation on caitsith.sourceforge
is lacking.

In any event, it seems like it might be worth testing performance of
tomoyo audit vs. hone. At least when the stacking issues are worked out.

 Cheers,
 peter

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-03  3:14                     ` Peter Moody
@ 2014-08-03  3:41                       ` Alex Elsayed
  2014-08-03 21:57                         ` Peter Moody
  0 siblings, 1 reply; 19+ messages in thread
From: Alex Elsayed @ 2014-08-03  3:41 UTC (permalink / raw)
  To: linux-security-module; +Cc: netdev

Peter Moody wrote:

> 
> On Sat, Aug 02 2014 at 19:47, Alex Elsayed wrote:
>>> #2012/04/08 05:03:03# global-pid=3720 result=allowed priority=100 / read
>>> path="/tmp/file1" task.pid=3720 task.ppid=3653 task.uid=0 task.gid=0
>>> task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0
>>> task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat"
>>> task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451
>>> path.major=8 path.minor=1 path.perm=0644 path.type=file
>>> path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0
>>> path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1
>>> path.parent.perm=01777 path.parent.type=directory
>>> path.parent.fsmagic=0xEF53
>>
>> Actually, now that I look at that, you'd need to audit 'domain
>> transition' events too - since that contains all the relevant PIDs, then
>> the most recent domain transition with all of the right PIDs is
>> sufficient to rebuild the tree back to init (recursively)
> 
> How are network events logged? The documentation on caitsith.sourceforge
> is lacking.

It depends on the event - if you look at the per-event docs[1], you'll see 
the variables it'll log. For instance, inet_stream_bind has 'ip', 'port', 
and 'task.$attribute' listed (and hyperlinked), so it'll log like this:

// These fields are common across all events:
// time, root-pid-ns PID, result, acl-priority, and chroot path
#2012/04/08 05:03:03# global-pid=3720 result=unmatched priority=0 /
// Then the action
inet_stream_bind
// then the variables
ip=0.0.0.0 port=80 task.pid=2245 task.ppid=3422 task.uid=81 task.gid=81
task.euid=81 task.egid=81 task.suid=0 task.sgid=0 task.fsuid=81
task.fsgid=81 task.type!=execute_handler task.exe="/user/bin/httpd"
task.domain="/usr/bin/httpd"

[1] Start at http://caitsith.sourceforge.jp/#5.26 and scroll


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-03  3:41                       ` Alex Elsayed
@ 2014-08-03 21:57                         ` Peter Moody
  2014-08-03 22:18                           ` Alex Elsayed
  0 siblings, 1 reply; 19+ messages in thread
From: Peter Moody @ 2014-08-03 21:57 UTC (permalink / raw)
  To: Alex Elsayed; +Cc: linux-security-module, netdev


On Sat, Aug 02 2014 at 20:41, Alex Elsayed wrote:
> Peter Moody wrote:
>
>> 
>> On Sat, Aug 02 2014 at 19:47, Alex Elsayed wrote:
>>>> #2012/04/08 05:03:03# global-pid=3720 result=allowed priority=100 / read
>>>> path="/tmp/file1" task.pid=3720 task.ppid=3653 task.uid=0 task.gid=0
>>>> task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0
>>>> task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat"
>>>> task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451
>>>> path.major=8 path.minor=1 path.perm=0644 path.type=file
>>>> path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0
>>>> path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1
>>>> path.parent.perm=01777 path.parent.type=directory
>>>> path.parent.fsmagic=0xEF53
>>>
>>> Actually, now that I look at that, you'd need to audit 'domain
>>> transition' events too - since that contains all the relevant PIDs, then
>>> the most recent domain transition with all of the right PIDs is
>>> sufficient to rebuild the tree back to init (recursively)
>> 
>> How are network events logged? The documentation on caitsith.sourceforge
>> is lacking.
>
> It depends on the event - if you look at the per-event docs[1], you'll see 
> the variables it'll log. For instance, inet_stream_bind has 'ip', 'port', 
> and 'task.$attribute' listed (and hyperlinked), so it'll log like this:

Is this all caitsaith-specific? I don't see how to test what you're
describing with tomoyo.

 Cheers,
 peter

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 0/2] RFC, aiding pid/network correlation
  2014-08-03 21:57                         ` Peter Moody
@ 2014-08-03 22:18                           ` Alex Elsayed
  0 siblings, 0 replies; 19+ messages in thread
From: Alex Elsayed @ 2014-08-03 22:18 UTC (permalink / raw)
  To: linux-security-module; +Cc: netdev

Peter Moody wrote:

> 
> On Sat, Aug 02 2014 at 20:41, Alex Elsayed wrote:
>> Peter Moody wrote:
>>
>>> 
>>> On Sat, Aug 02 2014 at 19:47, Alex Elsayed wrote:
>>>>> #2012/04/08 05:03:03# global-pid=3720 result=allowed priority=100 /
>>>>> #read
>>>>> path="/tmp/file1" task.pid=3720 task.ppid=3653 task.uid=0 task.gid=0
>>>>> task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0
>>>>> task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat"
>>>>> task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451
>>>>> path.major=8 path.minor=1 path.perm=0644 path.type=file
>>>>> path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0
>>>>> path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1
>>>>> path.parent.perm=01777 path.parent.type=directory
>>>>> path.parent.fsmagic=0xEF53
>>>>
>>>> Actually, now that I look at that, you'd need to audit 'domain
>>>> transition' events too - since that contains all the relevant PIDs,
>>>> then the most recent domain transition with all of the right PIDs is
>>>> sufficient to rebuild the tree back to init (recursively)
>>> 
>>> How are network events logged? The documentation on caitsith.sourceforge
>>> is lacking.
>>
>> It depends on the event - if you look at the per-event docs[1], you'll
>> see the variables it'll log. For instance, inet_stream_bind has 'ip',
>> 'port', and 'task.$attribute' listed (and hyperlinked), so it'll log like
>> this:
> 
> Is this all caitsaith-specific? I don't see how to test what you're
> describing with tomoyo.

Looking at Tomoyo, it seems to do it differently (and less conveniently) - 
the best way might be to:

1.) be in "permissive" mode so that "deny" doesn't actually prevent anything
2.) Set "grant_log=no" and "reject_log=yes" in the CONFIG section
3.) in acl_group zero, allow by default but deny network operations
4.) Watch the logs

It does seem like the logs are less verbose than CaitSith, though.

Note that CaitSith can be built as a kernel module (without patching), so 
that might be worth testing as well.


^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2014-08-03 22:18 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-01  1:21 [PATCH v2 0/2] RFC, aiding pid/network correlation Peter Moody
2014-08-01  1:21 ` [PATCH 1/2] security: create task_post_create callback Peter Moody
2014-08-01  1:21 ` [PATCH 2/2] security: Hone LSM Peter Moody
2014-08-01 12:16 ` [PATCH v2 0/2] RFC, aiding pid/network correlation Samir Bellabes
2014-08-01 17:22   ` Peter Moody
2014-08-02  0:30     ` Samir Bellabes
2014-08-02 15:05       ` Peter Moody
2014-08-02  4:55     ` Alex Elsayed
2014-08-03  1:34       ` Peter Moody
2014-08-03  1:49         ` Alex Elsayed
2014-08-03  2:19           ` Peter Moody
2014-08-03  2:28             ` Alex Elsayed
2014-08-03  2:38               ` Peter Moody
2014-08-03  2:41                 ` Alex Elsayed
2014-08-03  2:47                   ` Alex Elsayed
2014-08-03  3:14                     ` Peter Moody
2014-08-03  3:41                       ` Alex Elsayed
2014-08-03 21:57                         ` Peter Moody
2014-08-03 22:18                           ` Alex Elsayed

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.