diff mbox series

[net-next,15/20] net/neighbor: Update neightbl_dump_info for strict data checking

Message ID 20181004213355.14899-16-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 neightbl_dump_info for strict data checking. If the flag is set,
the dump request is expected to have an ndtmsg 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/core/neighbour.c | 38 +++++++++++++++++++++++++++++++++++---
 1 file changed, 35 insertions(+), 3 deletions(-)

Comments

Christian Brauner Oct. 7, 2018, 10:48 a.m. UTC | #1
On Thu, Oct 04, 2018 at 02:33:50PM -0700, David Ahern wrote:
> From: David Ahern <dsahern@gmail.com>
> 
> Update neightbl_dump_info for strict data checking. If the flag is set,
> the dump request is expected to have an ndtmsg 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/core/neighbour.c | 38 +++++++++++++++++++++++++++++++++++---
>  1 file changed, 35 insertions(+), 3 deletions(-)
> 
> diff --git a/net/core/neighbour.c b/net/core/neighbour.c
> index 3130d010b7ad..8e07b92403ab 100644
> --- a/net/core/neighbour.c
> +++ b/net/core/neighbour.c
> @@ -2164,15 +2164,47 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
>  	return err;
>  }
>  
> +static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
> +				    struct netlink_ext_ack *extack)
> +{
> +	struct ndtmsg *ndtm;
> +
> +	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
> +		NL_SET_ERR_MSG(extack, "Invalid header");
> +		return -EINVAL;
> +	}
> +
> +	ndtm = nlmsg_data(nlh);
> +	if (ndtm->ndtm_pad1  || ndtm->ndtm_pad2) {
> +		NL_SET_ERR_MSG(extack, "Invalid values in header for dump request");
> +		return -EINVAL;
> +	}
> +
> +	if (nlh->nlmsg_len != nlmsg_msg_size(sizeof(*ndtm))) {
> +		NL_SET_ERR_MSG(extack, "Invalid data after header");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
>  {
> +	const struct nlmsghdr *nlh = cb->nlh;
>  	struct net *net = sock_net(skb->sk);
>  	int family, tidx, nidx = 0;
>  	int tbl_skip = cb->args[0];
>  	int neigh_skip = cb->args[1];
>  	struct neigh_table *tbl;
>  
> -	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
> +	if (cb->strict_check) {
> +		int err = neightbl_valid_dump_info(nlh, cb->extack);
> +
> +		if (err)
> +			return err;
> +	}
> +
> +	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;

So this already was a problem prior to your patch: what happens when you
pass in the wrong struct? Then this case is not safe to do and might
contain all kinds of crap.

>  
>  	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
>  		struct neigh_parms *p;
> @@ -2185,7 +2217,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
>  			continue;
>  
>  		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
> -				       cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
> +				       nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
>  				       NLM_F_MULTI) < 0)
>  			break;
>  
> @@ -2200,7 +2232,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
>  
>  			if (neightbl_fill_param_info(skb, tbl, p,
>  						     NETLINK_CB(cb->skb).portid,
> -						     cb->nlh->nlmsg_seq,
> +						     nlh->nlmsg_seq,
>  						     RTM_NEWNEIGHTBL,
>  						     NLM_F_MULTI) < 0)
>  				goto out;
> -- 
> 2.11.0
>
David Ahern Oct. 8, 2018, 1:34 a.m. UTC | #2
On 10/7/18 4:48 AM, Christian Brauner wrote:
>> +
>>  static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
>>  {
>> +	const struct nlmsghdr *nlh = cb->nlh;
>>  	struct net *net = sock_net(skb->sk);
>>  	int family, tidx, nidx = 0;
>>  	int tbl_skip = cb->args[0];
>>  	int neigh_skip = cb->args[1];
>>  	struct neigh_table *tbl;
>>  
>> -	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
>> +	if (cb->strict_check) {
>> +		int err = neightbl_valid_dump_info(nlh, cb->extack);
>> +
>> +		if (err)
>> +			return err;
>> +	}
>> +
>> +	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
> 
> So this already was a problem prior to your patch: what happens when you
> pass in the wrong struct? Then this case is not safe to do and might
> contain all kinds of crap.

'This case' meaning the above dereference? family is *always* the first
element in all of the header structs. It is core to the rtnetlink
processing.
diff mbox series

Patch

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 3130d010b7ad..8e07b92403ab 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2164,15 +2164,47 @@  static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
 	return err;
 }
 
+static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
+				    struct netlink_ext_ack *extack)
+{
+	struct ndtmsg *ndtm;
+
+	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
+		NL_SET_ERR_MSG(extack, "Invalid header");
+		return -EINVAL;
+	}
+
+	ndtm = nlmsg_data(nlh);
+	if (ndtm->ndtm_pad1  || ndtm->ndtm_pad2) {
+		NL_SET_ERR_MSG(extack, "Invalid values in header for dump request");
+		return -EINVAL;
+	}
+
+	if (nlh->nlmsg_len != nlmsg_msg_size(sizeof(*ndtm))) {
+		NL_SET_ERR_MSG(extack, "Invalid data after header");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	const struct nlmsghdr *nlh = cb->nlh;
 	struct net *net = sock_net(skb->sk);
 	int family, tidx, nidx = 0;
 	int tbl_skip = cb->args[0];
 	int neigh_skip = cb->args[1];
 	struct neigh_table *tbl;
 
-	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
+	if (cb->strict_check) {
+		int err = neightbl_valid_dump_info(nlh, cb->extack);
+
+		if (err)
+			return err;
+	}
+
+	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
 
 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
 		struct neigh_parms *p;
@@ -2185,7 +2217,7 @@  static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 			continue;
 
 		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
-				       cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
+				       nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
 				       NLM_F_MULTI) < 0)
 			break;
 
@@ -2200,7 +2232,7 @@  static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 
 			if (neightbl_fill_param_info(skb, tbl, p,
 						     NETLINK_CB(cb->skb).portid,
-						     cb->nlh->nlmsg_seq,
+						     nlh->nlmsg_seq,
 						     RTM_NEWNEIGHTBL,
 						     NLM_F_MULTI) < 0)
 				goto out;