diff mbox

[RFC,net-next,1/9] netlink: add NLM_F_STRICT for strict attribute checking

Message ID 7631c32889e520fcc0da8c7898978b20e8453884.1444926905.git.jbenc@redhat.com
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

Jiri Benc Oct. 15, 2015, 4:39 p.m. UTC
When NLM_F_STRICT flag is set in a request, the message should undergo
stricter check for compatibility with the current kernel, or EPROTO should
be returned if such check could not be performed. In addition, NLM_F_STRICT
is set in error/ack reply to a request with this flag set.

For now, always return EPROTO.

Signed-off-by: Jiri Benc <jbenc@redhat.com>
---
 crypto/crypto_user.c              |  2 +-
 drivers/infiniband/core/netlink.c |  2 +-
 include/net/netlink.h             |  2 +-
 include/uapi/linux/netlink.h      |  1 +
 net/core/rtnetlink.c              |  2 +-
 net/core/sock_diag.c              |  2 +-
 net/netfilter/nfnetlink.c         |  6 +++++-
 net/netlink/af_netlink.c          | 14 +++++++++++---
 net/netlink/genetlink.c           |  2 +-
 net/xfrm/xfrm_user.c              |  2 +-
 10 files changed, 24 insertions(+), 11 deletions(-)
diff mbox

Patch

diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
index d94d99ffe8b9..8d46d3b69bee 100644
--- a/crypto/crypto_user.c
+++ b/crypto/crypto_user.c
@@ -526,7 +526,7 @@  static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 static void crypto_netlink_rcv(struct sk_buff *skb)
 {
 	mutex_lock(&crypto_cfg_mutex);
-	netlink_rcv_skb(skb, &crypto_user_rcv_msg);
+	netlink_rcv_skb(skb, false, &crypto_user_rcv_msg);
 	mutex_unlock(&crypto_cfg_mutex);
 }
 
diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c
index d47df9356779..1429c0cf583b 100644
--- a/drivers/infiniband/core/netlink.c
+++ b/drivers/infiniband/core/netlink.c
@@ -223,7 +223,7 @@  static void ibnl_rcv(struct sk_buff *skb)
 {
 	mutex_lock(&ibnl_mutex);
 	ibnl_rcv_reply_skb(skb);
-	netlink_rcv_skb(skb, &ibnl_rcv_msg);
+	netlink_rcv_skb(skb, false, &ibnl_rcv_msg);
 	mutex_unlock(&ibnl_mutex);
 }
 
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 0e3172751755..160e98cea304 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -228,7 +228,7 @@  struct nl_info {
 	u32			portid;
 };
 
-int netlink_rcv_skb(struct sk_buff *skb,
+int netlink_rcv_skb(struct sk_buff *skb, bool strict_supported,
 		    int (*cb)(struct sk_buff *, struct nlmsghdr *));
 int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid,
 		 unsigned int group, int report, gfp_t flags);
diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h
index f095155d8749..c001551fcedd 100644
--- a/include/uapi/linux/netlink.h
+++ b/include/uapi/linux/netlink.h
@@ -55,6 +55,7 @@  struct nlmsghdr {
 #define NLM_F_ECHO		8	/* Echo this request 		*/
 #define NLM_F_DUMP_INTR		16	/* Dump was inconsistent due to sequence change */
 #define NLM_F_DUMP_FILTERED	32	/* Dump was filtered as requested */
+#define NLM_F_STRICT		64	/* Fail if an attr is unsupported */
 
 /* Modifiers to GET request */
 #define NLM_F_ROOT	0x100	/* specify tree	root	*/
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 24775953fa68..afb41c7492b4 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -3356,7 +3356,7 @@  static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 static void rtnetlink_rcv(struct sk_buff *skb)
 {
 	rtnl_lock();
-	netlink_rcv_skb(skb, &rtnetlink_rcv_msg);
+	netlink_rcv_skb(skb, false, &rtnetlink_rcv_msg);
 	rtnl_unlock();
 }
 
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index 0c1d58d43f67..3aac827d1d67 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -272,7 +272,7 @@  static DEFINE_MUTEX(sock_diag_mutex);
 static void sock_diag_rcv(struct sk_buff *skb)
 {
 	mutex_lock(&sock_diag_mutex);
-	netlink_rcv_skb(skb, &sock_diag_rcv_msg);
+	netlink_rcv_skb(skb, false, &sock_diag_rcv_msg);
 	mutex_unlock(&sock_diag_mutex);
 }
 
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index f1d9e887f5b1..f7588dec4d23 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -339,6 +339,10 @@  replay:
 			err = -EINVAL;
 			goto ack;
 		}
+		if (nlh->nlmsg_flags & NLM_F_STRICT) {
+			err = -EPROTO;
+			goto ack;
+		}
 
 		type = nlh->nlmsg_type;
 		if (type == NFNL_MSG_BATCH_BEGIN) {
@@ -476,7 +480,7 @@  static void nfnetlink_rcv(struct sk_buff *skb)
 			res_id = ntohs(nfgenmsg->res_id);
 		nfnetlink_rcv_batch(skb, nlh, res_id);
 	} else {
-		netlink_rcv_skb(skb, &nfnetlink_rcv_msg);
+		netlink_rcv_skb(skb, false, &nfnetlink_rcv_msg);
 	}
 }
 
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 8f060d7f9a0e..d59d02038128 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2944,6 +2944,7 @@  void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
 	struct nlmsgerr *errmsg;
 	size_t payload = sizeof(*errmsg);
 	struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk);
+	unsigned int flags = 0;
 
 	/* Error messages get the original request appened, unless the user
 	 * requests to cap the error message.
@@ -2967,8 +2968,10 @@  void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
 		return;
 	}
 
+	if (nlh->nlmsg_flags & NLM_F_STRICT)
+		flags |= NLM_F_STRICT;
 	rep = __nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
-			  NLMSG_ERROR, payload, 0);
+			  NLMSG_ERROR, payload, flags);
 	errmsg = nlmsg_data(rep);
 	errmsg->error = err;
 	memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh));
@@ -2976,8 +2979,8 @@  void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
 }
 EXPORT_SYMBOL(netlink_ack);
 
-int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
-						     struct nlmsghdr *))
+int netlink_rcv_skb(struct sk_buff *skb, bool strict_supported,
+		    int (*cb)(struct sk_buff *, struct nlmsghdr *))
 {
 	struct nlmsghdr *nlh;
 	int err;
@@ -2995,6 +2998,11 @@  int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
 		if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
 			goto ack;
 
+		if (!strict_supported && (nlh->nlmsg_flags & NLM_F_STRICT)) {
+			err = -EPROTO;
+			goto ack;
+		}
+
 		/* Skip control messages */
 		if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
 			goto ack;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index bc0e504f33a6..d7bf14420c9e 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -667,7 +667,7 @@  static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 static void genl_rcv(struct sk_buff *skb)
 {
 	down_read(&cb_lock);
-	netlink_rcv_skb(skb, &genl_rcv_msg);
+	netlink_rcv_skb(skb, false, &genl_rcv_msg);
 	up_read(&cb_lock);
 }
 
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index a8de9e300200..bcde073f59db 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -2491,7 +2491,7 @@  static void xfrm_netlink_rcv(struct sk_buff *skb)
 	struct net *net = sock_net(skb->sk);
 
 	mutex_lock(&net->xfrm.xfrm_cfg_mutex);
-	netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
+	netlink_rcv_skb(skb, false, &xfrm_user_rcv_msg);
 	mutex_unlock(&net->xfrm.xfrm_cfg_mutex);
 }