diff mbox series

[net-next,18/20] net/ipv6: Update ip6addrlbl_dump for strict data checking

Message ID 20181004213355.14899-19-dsahern@kernel.org
State Changes Requested, archived
Delegated to: David Miller
Headers show
Series rtnetlink: Add support for rigid checking of data in dump request | expand

Commit Message

David Ahern Oct. 4, 2018, 9:33 p.m. UTC
From: David Ahern <dsahern@gmail.com>

Update ip6addrlbl_dump for strict data checking. If the flag is set,
the dump request is expected to have an ifaddrlblmsg struct as the
header. All elements of the struct are expected to be 0 and no
attributes can be appended.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 net/ipv6/addrlabel.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

Comments

Christian Brauner Oct. 7, 2018, 10:54 a.m. UTC | #1
On Thu, Oct 04, 2018 at 02:33:53PM -0700, David Ahern wrote:
> From: David Ahern <dsahern@gmail.com>
> 
> Update ip6addrlbl_dump for strict data checking. If the flag is set,
> the dump request is expected to have an ifaddrlblmsg struct as the
> header. All elements of the struct are expected to be 0 and no
> attributes can be appended.
> 
> Signed-off-by: David Ahern <dsahern@gmail.com>

Acked-by: Christian Brauner <christian@brauner.io>

> ---
>  net/ipv6/addrlabel.c | 35 ++++++++++++++++++++++++++++++++++-
>  1 file changed, 34 insertions(+), 1 deletion(-)
> 
> diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
> index 1d6ced37ad71..10556049cc44 100644
> --- a/net/ipv6/addrlabel.c
> +++ b/net/ipv6/addrlabel.c
> @@ -458,20 +458,53 @@ static int ip6addrlbl_fill(struct sk_buff *skb,
>  	return 0;
>  }
>  
> +static int ip6addrlbl_valid_dump_req(const struct nlmsghdr *nlh,
> +				     struct netlink_ext_ack *extack)
> +{
> +	struct ifaddrlblmsg *ifal;
> +
> +	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifal))) {
> +		NL_SET_ERR_MSG(extack, "Invalid header");
> +		return -EINVAL;
> +	}
> +
> +	ifal = nlmsg_data(nlh);
> +	if (ifal->__ifal_reserved || ifal->ifal_prefixlen ||
> +	    ifal->ifal_flags || ifal->ifal_index || ifal->ifal_seq) {
> +		NL_SET_ERR_MSG(extack,
> +			       "Invalid values in header for dump request");
> +		return -EINVAL;
> +	}
> +
> +	if (nlh->nlmsg_len != nlmsg_msg_size(sizeof(*ifal))) {
> +		NL_SET_ERR_MSG(extack, "Invalid data after header");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
>  {
> +	const struct nlmsghdr *nlh = cb->nlh;
>  	struct net *net = sock_net(skb->sk);
>  	struct ip6addrlbl_entry *p;
>  	int idx = 0, s_idx = cb->args[0];
>  	int err;
>  
> +	if (cb->strict_check) {
> +		err = ip6addrlbl_valid_dump_req(nlh, cb->extack);
> +		if (err)
> +			return err;
> +	}
> +
>  	rcu_read_lock();
>  	hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) {
>  		if (idx >= s_idx) {
>  			err = ip6addrlbl_fill(skb, p,
>  					      net->ipv6.ip6addrlbl_table.seq,
>  					      NETLINK_CB(cb->skb).portid,
> -					      cb->nlh->nlmsg_seq,
> +					      nlh->nlmsg_seq,
>  					      RTM_NEWADDRLABEL,
>  					      NLM_F_MULTI);
>  			if (err < 0)
> -- 
> 2.11.0
>
diff mbox series

Patch

diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 1d6ced37ad71..10556049cc44 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -458,20 +458,53 @@  static int ip6addrlbl_fill(struct sk_buff *skb,
 	return 0;
 }
 
+static int ip6addrlbl_valid_dump_req(const struct nlmsghdr *nlh,
+				     struct netlink_ext_ack *extack)
+{
+	struct ifaddrlblmsg *ifal;
+
+	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifal))) {
+		NL_SET_ERR_MSG(extack, "Invalid header");
+		return -EINVAL;
+	}
+
+	ifal = nlmsg_data(nlh);
+	if (ifal->__ifal_reserved || ifal->ifal_prefixlen ||
+	    ifal->ifal_flags || ifal->ifal_index || ifal->ifal_seq) {
+		NL_SET_ERR_MSG(extack,
+			       "Invalid values in header for dump request");
+		return -EINVAL;
+	}
+
+	if (nlh->nlmsg_len != nlmsg_msg_size(sizeof(*ifal))) {
+		NL_SET_ERR_MSG(extack, "Invalid data after header");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	const struct nlmsghdr *nlh = cb->nlh;
 	struct net *net = sock_net(skb->sk);
 	struct ip6addrlbl_entry *p;
 	int idx = 0, s_idx = cb->args[0];
 	int err;
 
+	if (cb->strict_check) {
+		err = ip6addrlbl_valid_dump_req(nlh, cb->extack);
+		if (err)
+			return err;
+	}
+
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) {
 		if (idx >= s_idx) {
 			err = ip6addrlbl_fill(skb, p,
 					      net->ipv6.ip6addrlbl_table.seq,
 					      NETLINK_CB(cb->skb).portid,
-					      cb->nlh->nlmsg_seq,
+					      nlh->nlmsg_seq,
 					      RTM_NEWADDRLABEL,
 					      NLM_F_MULTI);
 			if (err < 0)