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 |
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 >
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 --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;