lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20081112161058.25434.86923.stgit@paris.rdu.redhat.com>
Date:	Wed, 12 Nov 2008 11:10:58 -0500
From:	Eric Paris <eparis@...hat.com>
To:	linux-kernel@...r.kernel.org, malware-list@...ts.printk.net
Cc:	viro@...iv.linux.org.uk, alan@...rguk.ukuu.org.uk,
	arjan@...radead.org, greg@...ah.com, tytso@....edu,
	akpm@...ux-foundation.org
Subject: [PATCH =-v3 06/21] fanotify: add a userspace interface for fanotify
	notifications

notifications from fanotify need a userspace interface.  We are going to
try to do it with sockets.  Scary....

Signed-off-by: Eric Paris <eparis@...hat.com>
---

 include/linux/fanotify.h   |   29 ++++-
 include/linux/socket.h     |    5 +
 net/Makefile               |    1 
 net/core/sock.c            |    6 +
 net/fanotify/Makefile      |    5 +
 net/fanotify/af_fanotify.c |  240 ++++++++++++++++++++++++++++++++++++++++++++
 net/fanotify/af_fanotify.h |   20 ++++
 7 files changed, 294 insertions(+), 12 deletions(-)
 create mode 100644 net/fanotify/Makefile
 create mode 100644 net/fanotify/af_fanotify.c
 create mode 100644 net/fanotify/af_fanotify.h

diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
index c991bd9..76d88fd 100644
--- a/include/linux/fanotify.h
+++ b/include/linux/fanotify.h
@@ -34,17 +34,23 @@
 			 FAN_CLOSE |\
 			 FAN_OPEN)
 
-#ifdef __KERNEL__
 #include <linux/types.h>
-#else
-#include <stdint.h>
-#include <sys/types.h>
-#endif
 
+struct fanotify_addr {
+        __u32 group_num;
+        __u32 mask;
+        __u32 timeout;
+        __u32 unused[9];
+}  __attribute__((packed));
+
+/* struct used for FANOTIFY_GET_EVENT */
 struct fanotify_event_metadata {
-	int32_t fd;
-	uint32_t mask;
-};
+	__s32 fd;
+	__u32 mask;
+}  __attribute__((packed));
+
+/* fanotify getsockopt optvals */
+#define FANOTIFY_GET_EVENT	1
 
 #ifdef __KERNEL__
 
@@ -74,6 +80,8 @@ extern void fanotify(struct file *file, unsigned int mask);
 extern void fanotify_get_group(struct fanotify_group *group);
 extern struct fanotify_group *fanotify_find_group(unsigned int group_num, unsigned int mask);
 extern void fanotify_put_group(struct fanotify_group *group);
+
+extern int fanotify_create_event_fd(struct fanotify_group *group, struct fanotify_event_metadata *data, int nonblock);
 #else
 
 static inline void fanotify(struct file *file, unsigned int mask)
@@ -90,6 +98,11 @@ static inline struct fanotify_group *fanotify_find_group(unsigned int group_num,
 static inline extern void fanotify_put_group(struct fanotify_group *group)
 {}
 
+static inline int fanotify_create_event_fd(struct fanotify_group *group, struct fanotify_event_metadata *data, int nonblock)
+{
+	memset(data, 0, sizeof(struct fanotify_event_metadata));
+	return 0;
+}
 #endif	/* CONFIG_FANOTIFY */
 
 #endif	/* __KERNEL __ */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 20fc4bb..4fe7b83 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -191,7 +191,8 @@ struct ucred {
 #define AF_RXRPC	33	/* RxRPC sockets 		*/
 #define AF_ISDN		34	/* mISDN sockets 		*/
 #define AF_PHONET	35	/* Phonet sockets		*/
-#define AF_MAX		36	/* For now.. */
+#define AF_FANOTIFY	36	/* fscking all access sockets	*/
+#define AF_MAX		37	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -229,6 +230,7 @@ struct ucred {
 #define PF_RXRPC	AF_RXRPC
 #define PF_ISDN		AF_ISDN
 #define PF_PHONET	AF_PHONET
+#define PF_FANOTIFY	AF_FANOTIFY
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
@@ -298,6 +300,7 @@ struct ucred {
 #define SOL_PPPOL2TP	273
 #define SOL_BLUETOOTH	274
 #define SOL_PNPIPE	275
+#define SOL_FANOTIFY	276
 
 /* IPX options */
 #define IPX_TYPE	1
diff --git a/net/Makefile b/net/Makefile
index 27d1f10..5b98ba4 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_ATM)		+= atm/
 obj-$(CONFIG_DECNET)		+= decnet/
 obj-$(CONFIG_ECONET)		+= econet/
 obj-$(CONFIG_PHONET)		+= phonet/
+obj-$(CONFIG_FANOTIFY)		+= fanotify/
 ifneq ($(CONFIG_VLAN_8021Q),)
 obj-y				+= 8021q/
 endif
diff --git a/net/core/sock.c b/net/core/sock.c
index 5e2a313..c7b0cee 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -155,7 +155,7 @@ static const char *af_family_key_strings[AF_MAX+1] = {
   "sk_lock-27"       , "sk_lock-28"          , "sk_lock-AF_CAN"      ,
   "sk_lock-AF_TIPC"  , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV"        ,
   "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN"     , "sk_lock-AF_PHONET"   ,
-  "sk_lock-AF_MAX"
+  "sk_lock-AF_FANOTIFY", "sk_lock-AF_MAX"
 };
 static const char *af_family_slock_key_strings[AF_MAX+1] = {
   "slock-AF_UNSPEC", "slock-AF_UNIX"     , "slock-AF_INET"     ,
@@ -170,7 +170,7 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = {
   "slock-27"       , "slock-28"          , "slock-AF_CAN"      ,
   "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_IUCV"     ,
   "slock-AF_RXRPC" , "slock-AF_ISDN"     , "slock-AF_PHONET"   ,
-  "slock-AF_MAX"
+  "slock=AF_FANOTIFY", "slock-AF_MAX"
 };
 static const char *af_family_clock_key_strings[AF_MAX+1] = {
   "clock-AF_UNSPEC", "clock-AF_UNIX"     , "clock-AF_INET"     ,
@@ -185,7 +185,7 @@ static const char *af_family_clock_key_strings[AF_MAX+1] = {
   "clock-27"       , "clock-28"          , "clock-AF_CAN"      ,
   "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_IUCV"     ,
   "clock-AF_RXRPC" , "clock-AF_ISDN"     , "clock-AF_PHONET"   ,
-  "clock-AF_MAX"
+  "clock-AF_FANOTIFY", "clock-AF_MAX"
 };
 #endif
 
diff --git a/net/fanotify/Makefile b/net/fanotify/Makefile
new file mode 100644
index 0000000..348cf5e
--- /dev/null
+++ b/net/fanotify/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the fanotify AF.
+#
+
+obj-$(CONFIG_FANOTIFY) += af_fanotify.o
diff --git a/net/fanotify/af_fanotify.c b/net/fanotify/af_fanotify.c
new file mode 100644
index 0000000..7474cf1
--- /dev/null
+++ b/net/fanotify/af_fanotify.c
@@ -0,0 +1,240 @@
+#include <linux/errno.h>
+#include <linux/fanotify.h>
+#include <linux/fdtable.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/types.h>
+
+#include <net/net_namespace.h>
+#include <net/sock.h>
+
+#include "af_fanotify.h"
+
+static const struct proto_ops fanotify_proto_ops;
+
+static struct proto fanotify_proto = {
+	.name     = "FANOTIFY",
+	.owner    = THIS_MODULE,
+	.obj_size = sizeof(struct fanotify_sock),
+};
+
+static int fan_sock_create(struct net *net, struct socket *sock, int protocol)
+{
+	struct sock *sk;
+	struct fanotify_sock *fan_sock;
+
+	/* FIXME maybe a new LSM hook? */
+	if (!capable(CAP_NET_RAW))
+		return -EPERM;
+
+	if (protocol != 0)
+		return -ESOCKTNOSUPPORT;
+
+	if (sock->type != SOCK_RAW)
+		return -ESOCKTNOSUPPORT;
+
+	sock->state = SS_UNCONNECTED;
+
+	sk = sk_alloc(net, PF_FANOTIFY, GFP_KERNEL, &fanotify_proto);
+	if (sk == NULL)
+		return -ENOBUFS;
+
+	sock->ops = &fanotify_proto_ops;
+
+	sock_init_data(sock, sk);
+
+	sk->sk_family = PF_FANOTIFY;
+	//sk->sk_destruct = packet_sock_destruct;
+	sk_refcnt_debug_inc(sk);
+
+	fan_sock = fan_sk(sk);
+	fan_sock->group = NULL;
+
+	return 0;
+}
+
+static int fan_release(struct socket *sock)
+{
+	struct sock *sk;
+	struct fanotify_sock *fan_sock;
+
+	struct files_struct *files;
+	struct socket *testsock;
+	struct fdtable *fdt;
+	long j = -1;
+	unsigned long set, i;
+	int found = 0, err;
+
+	sk = sock->sk;
+	if (!sk)
+		return 0;
+
+	fan_sock = fan_sk(sk);
+
+	if (sock->state == SS_CONNECTED) {
+		sock->state = SS_UNCONNECTED;
+		fanotify_put_group(fan_sock->group);
+	}
+
+	fan_sock->group = NULL;
+
+	sock_orphan(sk);
+	sock->sk = NULL;
+
+	/* Purge queues */
+
+	sk_refcnt_debug_release(sk);
+
+	sock_put(sk);
+
+	/*
+	 * we do all of this shit to figure out if this process is closing the last
+	 * fanotify socket.  If this is the last one being closed we clear the
+	 * exclusion flag.  If this is not the last close we should remain excluded.
+	 *
+	 * the basic idea behind running all of the open fd's was stolen from
+	 * fs/exec.c:flush_old_files.
+	 */
+	files = current->files;
+	if (files)
+		spin_lock(&files->file_lock);
+	for (; !found && files ;) {
+		j++;
+		i = j * __NFDBITS;
+		fdt = files_fdtable(files);
+		if (i >= fdt->max_fds)
+			break;
+		set = fdt->open_fds->fds_bits[j];
+		if (!set)
+			continue;
+		spin_unlock(&files->file_lock);
+		for ( ; set && !found ; i++, set >>= 1) {
+			if (set & 1) {
+				testsock = sockfd_lookup(i, &err);
+				if (!testsock)
+					continue;
+				if ((testsock != sock) && (testsock->ops == &fanotify_proto_ops))
+					found = 1;
+				sockfd_put(testsock);
+			}
+		}
+		spin_lock(&files->file_lock);
+	}
+	if (files)
+		spin_unlock(&files->file_lock);
+
+	if (!found)
+		current->flags &= ~PF_NOFACCESS;
+
+	return 0;
+}
+
+static int fan_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+{
+	struct fanotify_addr *fan_addr = (struct fanotify_addr *)addr;
+	struct fanotify_sock *fan_sock;
+
+	if (addr_len != sizeof(struct fanotify_addr))
+		return -EINVAL;
+
+	if (sock->state != SS_UNCONNECTED)
+		return -EINVAL;
+
+	fan_sock = fan_sk(sock->sk);
+	fan_sock->group = fanotify_find_group(fan_addr->group_num, fan_addr->mask);
+
+	if (IS_ERR(fan_sock->group))
+		return PTR_ERR(fan_sock->group);
+
+	sock->state = SS_CONNECTED;
+	current->flags |= PF_NOFACCESS;
+
+	return 0;
+}
+
+static int fan_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+{
+	struct fanotify_sock *fan_sock;
+	struct fanotify_group *group;
+	union {
+		struct fanotify_event_metadata event_metadata;
+	} data;
+	int len, ret = 0;
+
+	if (get_user(len, optlen))
+		return -EFAULT;
+
+	if (sock->state != SS_CONNECTED)
+		return -EBADF;
+
+	if (level != SOL_FANOTIFY)
+		return -ENOPROTOOPT;
+
+	fan_sock = fan_sk(sock->sk);
+	group = fan_sock->group;
+
+	switch (optname) {
+	case FANOTIFY_GET_EVENT:
+		if (len < sizeof(struct fanotify_event_metadata))
+			return -ENOMEM;
+		else
+			len = sizeof(struct fanotify_event_metadata);
+		ret = fanotify_create_event_fd(group, &data.event_metadata, !!(sock->file->f_flags & O_NONBLOCK));
+		if (ret)
+			break;
+
+		ret = copy_to_user(optval, &data.event_metadata, sizeof(struct fanotify_event_metadata));
+		break;
+	default:
+		return -ENOPROTOOPT;
+	};
+
+	if (!ret)
+		ret = put_user(len, optlen);
+
+	return ret;
+}
+
+static const struct net_proto_family fanotify_family_ops = {
+	.family		=	PF_FANOTIFY,
+	.create		=	fan_sock_create,
+	.owner		=	THIS_MODULE,
+};
+
+static const struct proto_ops fanotify_proto_ops = {
+	.family =	PF_FANOTIFY,
+	.owner =	THIS_MODULE,
+	.release =	fan_release,
+	.bind =		fan_bind,
+	.connect =	sock_no_connect,
+	.socketpair =	sock_no_socketpair,
+	.accept =	sock_no_accept,
+	.getname =	sock_no_getname,
+	.poll =		sock_no_poll,
+	.ioctl =	sock_no_ioctl,
+	.listen =	sock_no_listen,
+	.shutdown =	sock_no_shutdown,
+	.setsockopt =	sock_no_setsockopt,
+	.getsockopt =	fan_getsockopt,
+	.sendmsg =	sock_no_sendmsg,
+	.recvmsg =	sock_no_recvmsg,
+	.mmap =		sock_no_mmap,
+	.sendpage =	sock_no_sendpage,
+};
+
+static int __init fanotify_socket_register(void)
+{
+	int rc = proto_register(&fanotify_proto, 0);
+
+	if (rc != 0)
+		goto out;
+
+	sock_register(&fanotify_family_ops);
+out:
+	return rc;
+}
+__initcall(fanotify_socket_register);
diff --git a/net/fanotify/af_fanotify.h b/net/fanotify/af_fanotify.h
new file mode 100644
index 0000000..a987d7b
--- /dev/null
+++ b/net/fanotify/af_fanotify.h
@@ -0,0 +1,20 @@
+#ifndef _LINUX_AF_FANOTIFY_H
+#define _LINUX_AF_FANOTIFY_H
+
+#ifdef __KERNEL__
+
+#include <linux/fanotify.h>
+#include <net/sock.h>
+
+struct fanotify_sock {
+	struct sock		sock;
+	struct fanotify_group	*group;
+};
+
+static inline struct fanotify_sock *fan_sk(struct sock *sock)
+{
+	return (struct fanotify_sock *)sock;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_AF_NET_H */

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ