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]
Date:   Mon, 11 Dec 2017 12:38:36 -0800
From:   Tom Herbert <tom@...ntonium.net>
To:     davem@...emloft.net
Cc:     netdev@...r.kernel.org, roopa@...ulusnetworks.com,
        rohit@...ntonium.net, Tom Herbert <tom@...ntonium.net>
Subject: [PATCH v3 net-next 8/9] resolver: add netlink control

Add interfaces into resolver backend that can be used to provide
netlink. The interface includes fucntions to support the common
netlink commands (get, add, list, delete, and flush). The
frontend that is using the resolver implements the actual
netlink interfaces for its service and calls the backend functions
to provide netlink for the resolver.

Signed-off-by: Tom Herbert <tom@...ntonium.net>
---
 include/net/resolver.h      |  26 +++-
 net/ipv6/ila/ila_resolver.c |   3 +-
 net/resolver/resolver.c     | 280 +++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 305 insertions(+), 4 deletions(-)

diff --git a/include/net/resolver.h b/include/net/resolver.h
index f38c7e9f1205..307938ad91a6 100644
--- a/include/net/resolver.h
+++ b/include/net/resolver.h
@@ -14,12 +14,21 @@
 
 #include <linux/rhashtable.h>
 #include <linux/types.h>
+#include <net/genetlink.h>
+#include <uapi/linux/genetlink.h>
 
 struct net_rslv;
 
 typedef int (*net_rslv_cmpfn)(struct net_rslv *nrslv, const void *key,
 			      const void *object);
 
+struct net_rslv_netlink_map {
+	int dst_attr;
+	int timo_attr;
+	int get_cmd;
+	struct genl_family *genl_family;
+};
+
 struct net_rslv {
 	struct rhashtable rhash_table;
 	struct rhashtable_params params;
@@ -28,10 +37,12 @@ struct net_rslv {
 	spinlock_t *locks;
 	unsigned int locks_mask;
 	unsigned int hash_rnd;
+	const struct net_rslv_netlink_map *nlmap;
 };
 
 struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len,
-				 size_t max_size, net_rslv_cmpfn cmp_fn);
+				 size_t max_size, net_rslv_cmpfn cmp_fn,
+				 const struct net_rslv_netlink_map *nlmap);
 
 void net_rslv_destroy(struct net_rslv *nrslv);
 
@@ -40,4 +51,17 @@ int net_rslv_lookup_and_create(struct net_rslv *nrslv, void *key,
 
 void net_rslv_resolved(struct net_rslv *nrslv, void *key);
 
+int net_rslv_nl_cmd_add(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info);
+int net_rslv_nl_cmd_del(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info);
+int net_rslv_nl_cmd_get(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info);
+int net_rslv_nl_cmd_flush(struct net_rslv *nrslv, struct sk_buff *skb,
+			  struct genl_info *info);
+int net_rslv_nl_dump_start(struct net_rslv *nrslv, struct netlink_callback *cb);
+int net_rslv_nl_dump_done(struct net_rslv *nrslv, struct netlink_callback *cb);
+int net_rslv_nl_dump(struct net_rslv *nrslv, struct sk_buff *skb,
+		     struct netlink_callback *cb);
+
 #endif /* __NET_RESOLVER_H */
diff --git a/net/ipv6/ila/ila_resolver.c b/net/ipv6/ila/ila_resolver.c
index 8b9a3c5305a4..2aebc0526221 100644
--- a/net/ipv6/ila/ila_resolver.c
+++ b/net/ipv6/ila/ila_resolver.c
@@ -215,7 +215,8 @@ int ila_rslv_init_net(struct net *net)
 	struct net_rslv *nrslv;
 
 	nrslv = net_rslv_create(sizeof(struct ila_addr),
-				sizeof(struct ila_addr), ILA_MAX_SIZE, NULL);
+				sizeof(struct ila_addr), ILA_MAX_SIZE, NULL,
+				NULL);
 
 	if (IS_ERR(nrslv))
 		return PTR_ERR(nrslv);
diff --git a/net/resolver/resolver.c b/net/resolver/resolver.c
index 32a915ed8f93..e2496b0bf852 100644
--- a/net/resolver/resolver.c
+++ b/net/resolver/resolver.c
@@ -19,11 +19,13 @@
 #include <linux/types.h>
 #include <linux/vmalloc.h>
 #include <net/checksum.h>
+#include <net/genetlink.h>
 #include <net/ip.h>
 #include <net/ip6_fib.h>
 #include <net/lwtunnel.h>
 #include <net/protocol.h>
 #include <net/resolver.h>
+#include <uapi/linux/genetlink.h>
 
 struct net_rslv_ent {
 	struct rhash_head node;
@@ -192,8 +194,8 @@ static int net_rslv_cmp(struct rhashtable_compare_arg *arg,
 #define MAX_LOCKS 1024
 
 struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len,
-				 size_t max_size,
-				 net_rslv_cmpfn cmp_fn)
+				 size_t max_size, net_rslv_cmpfn cmp_fn,
+				 const struct net_rslv_netlink_map *nlmap)
 {
 	struct net_rslv *nrslv;
 	int err;
@@ -212,6 +214,7 @@ struct net_rslv *net_rslv_create(size_t obj_size, size_t key_len,
 
 	nrslv->obj_size = obj_size;
 	nrslv->rslv_cmp = cmp_fn;
+	nrslv->nlmap = nlmap;
 	get_random_bytes(&nrslv->hash_rnd, sizeof(nrslv->hash_rnd));
 
 	nrslv->params.head_offset = offsetof(struct net_rslv_ent, node);
@@ -278,6 +281,279 @@ void net_rslv_destroy(struct net_rslv *nrslv)
 }
 EXPORT_SYMBOL_GPL(net_rslv_destroy);
 
+/* Netlink access utility functions and structures. */
+
+struct net_rslv_params {
+	unsigned int timeout;
+	__u8 key[MAX_ADDR_LEN];
+	size_t keysize;
+};
+
+static int parse_nl_config(struct net_rslv *nrslv, struct genl_info *info,
+			   struct net_rslv_params *np)
+{
+	if (!info->attrs[nrslv->nlmap->dst_attr] ||
+	    nla_len(info->attrs[nrslv->nlmap->dst_attr]) !=
+					nrslv->params.key_len)
+		return -EINVAL;
+
+	memset(np, 0, sizeof(*np));
+
+	memcpy(np->key, nla_data(info->attrs[nrslv->nlmap->dst_attr]),
+	       nla_len(info->attrs[nrslv->nlmap->dst_attr]));
+
+	if (info->attrs[nrslv->nlmap->timo_attr])
+		np->timeout = nla_get_u32(info->attrs[nrslv->nlmap->timo_attr]);
+
+	return 0;
+}
+
+int net_rslv_nl_cmd_add(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info)
+{
+	struct net_rslv_params p;
+	int err;
+
+	err = parse_nl_config(nrslv, info, &p);
+	if (err)
+		return err;
+
+	return net_rslv_lookup_and_create(nrslv, p.key, p.timeout);
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_add);
+
+int net_rslv_nl_cmd_del(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info)
+{
+	struct net_rslv_params p;
+	int err;
+
+	err = parse_nl_config(nrslv, info, &p);
+	if (err)
+		return err;
+
+	/* Treat removal as being resolved */
+	net_rslv_resolved(nrslv, p.key);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_del);
+
+static int net_rslv_fill_info(struct net_rslv *nrslv,
+			      struct net_rslv_ent *nrent,
+			      struct sk_buff *msg)
+{
+	int from_now = 0;
+
+	if (delayed_work_pending(&nrent->timeout_work)) {
+		unsigned long expires = nrent->timeout_work.timer.expires;
+
+		from_now = jiffies_to_msecs(expires - jiffies);
+
+		if (from_now < 0)
+			from_now = 0;
+	}
+
+	if (nla_put(msg, nrslv->nlmap->dst_attr, nrslv->params.key_len,
+		    nrent->object) ||
+	    nla_put_s32(msg, nrslv->nlmap->timo_attr, from_now))
+		return -1;
+
+	return 0;
+}
+
+static int net_rslv_dump_info(struct net_rslv *nrslv,
+			      struct net_rslv_ent *nrent, u32 portid, u32 seq,
+			      u32 flags, struct sk_buff *skb, u8 cmd)
+{
+	void *hdr;
+
+	hdr = genlmsg_put(skb, portid, seq, nrslv->nlmap->genl_family, flags,
+			  cmd);
+	if (!hdr)
+		return -ENOMEM;
+
+	if (net_rslv_fill_info(nrslv, nrent, skb) < 0)
+		goto nla_put_failure;
+
+	genlmsg_end(skb, hdr);
+	return 0;
+
+nla_put_failure:
+	genlmsg_cancel(skb, hdr);
+	return -EMSGSIZE;
+}
+
+int net_rslv_nl_cmd_get(struct net_rslv *nrslv, struct sk_buff *skb,
+			struct genl_info *info)
+{
+	struct net_rslv_ent *nrent;
+	struct net_rslv_params p;
+	struct sk_buff *msg;
+	int err;
+
+	err = parse_nl_config(nrslv, info, &p);
+	if (err)
+		return err;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	rcu_read_lock();
+
+	nrent = rhashtable_lookup_fast(&nrslv->rhash_table, p.key,
+				       nrslv->params);
+	if (nrent)
+		err = net_rslv_dump_info(nrslv, nrent, info->snd_portid,
+					 info->snd_seq, 0, msg,
+					 info->genlhdr->cmd);
+
+	rcu_read_unlock();
+
+	if (err < 0)
+		goto out_free;
+
+	return genlmsg_reply(msg, info);
+
+out_free:
+	nlmsg_free(msg);
+	return err;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_get);
+
+int net_rslv_nl_cmd_flush(struct net_rslv *nrslv, struct sk_buff *skb,
+			  struct genl_info *info)
+{
+	struct rhashtable_iter iter;
+	struct net_rslv_ent *nrent;
+	spinlock_t *lock;
+	int ret;
+
+	ret = rhashtable_walk_init(&nrslv->rhash_table, &iter, GFP_KERNEL);
+	if (ret)
+		return ret;
+
+	rhashtable_walk_start(&iter);
+
+	for (;;) {
+		nrent = rhashtable_walk_next(&iter);
+
+		if (IS_ERR(nrent)) {
+			if (PTR_ERR(nrent) == -EAGAIN) {
+				/* New table, we're okay to continue */
+				continue;
+			}
+			ret = PTR_ERR(nrent);
+			break;
+		} else if (!nrent) {
+			break;
+		}
+
+		lock = net_rslv_get_lock(nrslv, nrent->object);
+
+		spin_lock(lock);
+		ret = rhashtable_remove_fast(&nrslv->rhash_table, &nrent->node,
+					     nrslv->params);
+		spin_unlock(lock);
+
+		if (ret)
+			break;
+	}
+
+	rhashtable_walk_stop(&iter);
+	rhashtable_walk_exit(&iter);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_cmd_flush);
+
+int net_rslv_nl_dump_start(struct net_rslv *nrslv, struct netlink_callback *cb)
+{
+	struct rhashtable_iter *iter;
+	int ret;
+
+	iter = kmalloc(sizeof(*iter), GFP_KERNEL);
+	if (!iter)
+		return -ENOMEM;
+
+	ret = rhashtable_walk_init(&nrslv->rhash_table, iter, GFP_KERNEL);
+	if (ret) {
+		kfree(iter);
+		return ret;
+	}
+
+	cb->args[0] = (long)iter;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_dump_start);
+
+int net_rslv_nl_dump_done(struct net_rslv *nrslv, struct netlink_callback *cb)
+{
+	struct rhashtable_iter *iter =
+				(struct rhashtable_iter *)cb->args[0];
+
+	rhashtable_walk_exit(iter);
+
+	kfree(iter);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_dump_done);
+
+int net_rslv_nl_dump(struct net_rslv *nrslv, struct sk_buff *skb,
+		     struct netlink_callback *cb)
+{
+	struct rhashtable_iter *iter =
+				(struct rhashtable_iter *)cb->args[0];
+	struct net_rslv_ent *nrent;
+	int ret;
+
+	ret = rhashtable_walk_start_check(iter);
+	if (ret)
+		goto done;
+
+	/* Get first entty */
+	nrent = rhashtable_walk_peek(iter);
+
+	for (;;) {
+		if (IS_ERR(nrent)) {
+			ret = PTR_ERR(nrent);
+			if (ret == -EAGAIN) {
+				/* Table has changed and iter has reset. Return
+				 * -EAGAIN to the application even if we have
+				 * written data to the skb. The application
+				 * needs to deal with this.
+				 */
+
+				goto done;
+			}
+			break;
+		} else if (!nrent) {
+			break;
+		}
+
+		ret =  net_rslv_dump_info(nrslv, nrent,
+					  NETLINK_CB(cb->skb).portid,
+					  cb->nlh->nlmsg_seq,
+					  NLM_F_MULTI, skb,
+					  nrslv->nlmap->get_cmd);
+		if (ret)
+			break;
+
+		/* Get next and advance the iter */
+		nrent = rhashtable_walk_next(iter);
+	}
+
+	ret = (skb->len ? : ret);
+
+done:
+	rhashtable_walk_stop(iter);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(net_rslv_nl_dump);
+
 MODULE_AUTHOR("Tom Herbert <tom@...ntonium.net>");
 MODULE_LICENSE("GPL");
 
-- 
2.11.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ