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: <0fc799575dd3893a386cfa9be35b17bf9ced4094.1513000306.git.mkubecek@suse.cz>
Date:   Mon, 11 Dec 2017 14:53:41 +0100 (CET)
From:   Michal Kubecek <mkubecek@...e.cz>
To:     netdev@...r.kernel.org
Cc:     linux-kernel@...r.kernel.org
Subject: [RFC PATCH 3/9] ethtool: helper functions for netlink interface

Misc helpers used by ethtool netlink code.

Signed-off-by: Michal Kubecek <mkubecek@...e.cz>
---
 net/core/ethtool_netlink.c | 177 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 177 insertions(+)

diff --git a/net/core/ethtool_netlink.c b/net/core/ethtool_netlink.c
index 46a226bb9a2c..22d23d057623 100644
--- a/net/core/ethtool_netlink.c
+++ b/net/core/ethtool_netlink.c
@@ -8,6 +8,183 @@
 
 static struct genl_family ethtool_genl_family;
 
+/* misc helper functions */
+
+static int ethnl_str_size(const char *s)
+{
+	return nla_total_size(strlen(s) + 1);
+}
+
+static int ethnl_str_ifne_size(const char *s)
+{
+	return s[0] ? ethnl_str_size(s) : 0;
+}
+
+static int ethnl_put_str_ifne(struct sk_buff *skb, int attrtype, const char *s)
+{
+	if (!s[0])
+		return 0;
+	return nla_put_string(skb, attrtype, s);
+}
+
+static struct nlattr *ethnl_nest_start(struct sk_buff *skb, int attrtype)
+{
+	return nla_nest_start(skb, attrtype | NLA_F_NESTED);
+}
+
+/* ethnl_update_* return true if the value is changed */
+static bool ethnl_update_u32(u32 *dst, struct nlattr *attr)
+{
+	u32 val;
+
+	if (!attr)
+		return false;
+	val = nla_get_u32(attr);
+	if (*dst == val)
+		return false;
+
+	*dst = val;
+	return true;
+}
+
+static bool ethnl_update_u8(u8 *dst, struct nlattr *attr)
+{
+	u8 val;
+
+	if (!attr)
+		return false;
+	val = nla_get_u8(attr);
+	if (*dst == val)
+		return false;
+
+	*dst = val;
+	return true;
+}
+
+/* update u32 value used as bool from NLA_U8 */
+static bool ethnl_update_bool32(u32 *dst, struct nlattr *attr)
+{
+	u8 val;
+
+	if (!attr)
+		return false;
+	val = !!nla_get_u8(attr);
+	if (!!*dst == val)
+		return false;
+
+	*dst = val;
+	return true;
+}
+
+static bool ethnl_update_binary(u8 *dst, unsigned int len, struct nlattr *attr)
+{
+	if (!attr)
+		return false;
+	if (nla_len(attr) < len)
+		len = nla_len(attr);
+	if (!memcmp(dst, nla_data(attr), len))
+		return false;
+
+	memcpy(dst, nla_data(attr), len);
+	return true;
+}
+
+static bool ethnl_update_bitfield32(u32 *dst, struct nlattr *attr)
+{
+	struct nla_bitfield32 change;
+	u32 newval;
+
+	if (!attr)
+		return false;
+	change = nla_get_bitfield32(attr);
+	newval = (*dst & ~change.selector) | (change.value & change.selector);
+	if (*dst == newval)
+		return false;
+
+	*dst = newval;
+	return true;
+}
+
+static struct net_device *ethnl_dev_get(struct genl_info *info)
+{
+	const struct ethnlmsghdr *hdr = info->userhdr;
+	struct net *net = genl_info_net(info);
+	struct net_device *dev;
+
+	if (hdr->ifindex) {
+		dev = dev_get_by_index(net, hdr->ifindex);
+		if (!dev)
+			return ERR_PTR(-ENODEV);
+		/* if both ifindex and ifname are passed, both must match */
+		if (hdr->ifname && strncmp(dev->name, hdr->ifname, IFNAMSIZ)) {
+			GENL_SET_ERR_MSG(info,
+					 "ifindex and ifname do not match");
+			return ERR_PTR(-ENODEV);
+		}
+		return dev;
+	} else if (hdr->ifname[0]) {
+		dev = dev_get_by_name(net, hdr->ifname);
+		return dev ?: ERR_PTR(-ENODEV);
+	}
+
+	return ERR_PTR(-EINVAL);
+}
+
+static void warn_partial_info(struct genl_info *info)
+{
+	GENL_SET_ERR_MSG(info, "not all requested data could be retrieved");
+}
+
+/* Check user privileges explicitly to allow finer access control based on
+ * context of the request or hiding part of the information from unprivileged
+ * users
+ */
+static bool ethnl_is_privileged(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net *net = genl_info_net(info);
+
+	return netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN);
+}
+
+/* create skb for a reply
+ * payload: payload length (without netlink, genetlink and ethnl headers)
+ * dev:     device the reply is about
+ * cmd:     ETHTOOL_CMD_* command for reply
+ * info:   info for the received packet we respond to
+ * ehdrp:   place to store pointer to ethtool specific header (may be null)
+ * returns: skb or null on error
+ */
+static struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev,
+					u8 cmd, struct genl_info *info,
+					struct ethnlmsghdr **ehdrp)
+{
+	struct ethnlmsghdr *ehdr;
+	struct sk_buff *rskb;
+
+	rskb = genlmsg_new(ETHNL_HDRLEN + payload, GFP_KERNEL);
+	if (!rskb) {
+		GENL_SET_ERR_MSG(info,
+				 "failed to allocate reply message");
+		return NULL;
+	}
+
+	ehdr = genlmsg_put_reply(rskb, info, &ethtool_genl_family, 0, cmd);
+	if (!ehdr) {
+		nlmsg_free(rskb);
+		return NULL;
+	}
+	if (ehdrp)
+		*ehdrp = ehdr;
+
+	ehdr->ifindex = dev->ifindex;
+	ehdr->flags = 0;
+	ehdr->info_mask = 0;
+	strncpy(ehdr->ifname, dev->name, sizeof(ehdr->ifname));
+	ehdr->ifname[sizeof(ehdr->ifname) - 1] = '\0';
+
+	return rskb;
+}
+
 /* genetlink paperwork */
 
 static const struct genl_ops ethtool_genl_ops[] = {
-- 
2.15.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ