Commit e266afa9 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-use-strict-checks-in-doit-handlers'

Jakub Kicinski says:

====================
net: use strict checks in doit handlers

This series extends strict argument checking to doit handlers
of the GET* nature.  This is a bit tricky since strict checking
flag has already been released..

iproute2 did not have a release with strick checks enabled,
and it will only need a minor one-liner to pass strick checks
after all the work that DaveA has already done.

Big thanks to Dave Ahern for help and guidence.

v2:
 - remove unnecessary check in patch 5 (Nicolas);
 - add path 7 (DaveA);
 - improve messages in patch 8 (DaveA).
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 133bbb18 0c4056ee
......@@ -126,6 +126,7 @@ void __netlink_clear_multicast_users(struct sock *sk, unsigned int group);
void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
const struct netlink_ext_ack *extack);
int netlink_has_listeners(struct sock *sk, unsigned int group);
bool netlink_strict_get_check(struct sk_buff *skb);
int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid,
......
......@@ -778,6 +778,41 @@ static int rtnl_net_fill(struct sk_buff *skb, struct net_fill_args *args)
return -EMSGSIZE;
}
static int rtnl_net_valid_getid_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
int i, err;
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
rtnl_net_policy, extack);
err = nlmsg_parse_strict(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
rtnl_net_policy, extack);
if (err)
return err;
for (i = 0; i <= NETNSA_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case NETNSA_PID:
case NETNSA_FD:
case NETNSA_NSID:
case NETNSA_TARGET_NSID:
break;
default:
NL_SET_ERR_MSG(extack, "Unsupported attribute in peer netns getid request");
return -EINVAL;
}
}
return 0;
}
static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
......@@ -793,8 +828,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
struct sk_buff *msg;
int err;
err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
rtnl_net_policy, extack);
err = rtnl_net_valid_getid_req(skb, nlh, tb, extack);
if (err < 0)
return err;
if (tb[NETNSA_PID]) {
......
......@@ -3242,6 +3242,53 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
return ret;
}
static int rtnl_valid_getlink_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
struct ifinfomsg *ifm;
int i, err;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) {
NL_SET_ERR_MSG(extack, "Invalid header for get link");
return -EINVAL;
}
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy,
extack);
ifm = nlmsg_data(nlh);
if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags ||
ifm->ifi_change) {
NL_SET_ERR_MSG(extack, "Invalid values in header for get link request");
return -EINVAL;
}
err = nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy,
extack);
if (err)
return err;
for (i = 0; i <= IFLA_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case IFLA_IFNAME:
case IFLA_EXT_MASK:
case IFLA_TARGET_NETNSID:
break;
default:
NL_SET_ERR_MSG(extack, "Unsupported attribute in get link request");
return -EINVAL;
}
}
return 0;
}
static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
......@@ -3256,7 +3303,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
int err;
u32 ext_filter_mask = 0;
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack);
err = rtnl_valid_getlink_req(skb, nlh, tb, extack);
if (err < 0)
return err;
......@@ -4902,6 +4949,40 @@ static size_t if_nlmsg_stats_size(const struct net_device *dev,
return size;
}
static int rtnl_valid_stats_req(const struct nlmsghdr *nlh, bool strict_check,
bool is_dump, struct netlink_ext_ack *extack)
{
struct if_stats_msg *ifsm;
if (nlh->nlmsg_len < sizeof(*ifsm)) {
NL_SET_ERR_MSG(extack, "Invalid header for stats dump");
return -EINVAL;
}
if (!strict_check)
return 0;
ifsm = nlmsg_data(nlh);
/* only requests using strict checks can pass data to influence
* the dump. The legacy exception is filter_mask.
*/
if (ifsm->pad1 || ifsm->pad2 || (is_dump && ifsm->ifindex)) {
NL_SET_ERR_MSG(extack, "Invalid values in header for stats dump request");
return -EINVAL;
}
if (nlmsg_attrlen(nlh, sizeof(*ifsm))) {
NL_SET_ERR_MSG(extack, "Invalid attributes after stats header");
return -EINVAL;
}
if (ifsm->filter_mask >= IFLA_STATS_FILTER_BIT(IFLA_STATS_MAX + 1)) {
NL_SET_ERR_MSG(extack, "Invalid stats requested through filter mask");
return -EINVAL;
}
return 0;
}
static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
......@@ -4913,8 +4994,10 @@ static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh,
u32 filter_mask;
int err;
if (nlmsg_len(nlh) < sizeof(*ifsm))
return -EINVAL;
err = rtnl_valid_stats_req(nlh, netlink_strict_get_check(skb),
false, extack);
if (err)
return err;
ifsm = nlmsg_data(nlh);
if (ifsm->ifindex > 0)
......@@ -4966,27 +5049,11 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb)
cb->seq = net->dev_base_seq;
if (nlmsg_len(cb->nlh) < sizeof(*ifsm)) {
NL_SET_ERR_MSG(extack, "Invalid header for stats dump");
return -EINVAL;
}
err = rtnl_valid_stats_req(cb->nlh, cb->strict_check, true, extack);
if (err)
return err;
ifsm = nlmsg_data(cb->nlh);
/* only requests using strict checks can pass data to influence
* the dump. The legacy exception is filter_mask.
*/
if (cb->strict_check) {
if (ifsm->pad1 || ifsm->pad2 || ifsm->ifindex) {
NL_SET_ERR_MSG(extack, "Invalid values in header for stats dump request");
return -EINVAL;
}
if (nlmsg_attrlen(cb->nlh, sizeof(*ifsm))) {
NL_SET_ERR_MSG(extack, "Invalid attributes after stats header");
return -EINVAL;
}
}
filter_mask = ifsm->filter_mask;
if (!filter_mask) {
NL_SET_ERR_MSG(extack, "Filter mask must be set for stats dump");
......
......@@ -2063,13 +2063,49 @@ static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
};
static int inet_netconf_valid_get_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
int i, err;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) {
NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf get request");
return -EINVAL;
}
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(struct netconfmsg), tb,
NETCONFA_MAX, devconf_ipv4_policy, extack);
err = nlmsg_parse_strict(nlh, sizeof(struct netconfmsg), tb,
NETCONFA_MAX, devconf_ipv4_policy, extack);
if (err)
return err;
for (i = 0; i <= NETCONFA_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case NETCONFA_IFINDEX:
break;
default:
NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in netconf get request");
return -EINVAL;
}
}
return 0;
}
static int inet_netconf_get_devconf(struct sk_buff *in_skb,
struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(in_skb->sk);
struct nlattr *tb[NETCONFA_MAX+1];
struct netconfmsg *ncm;
struct sk_buff *skb;
struct ipv4_devconf *devconf;
struct in_device *in_dev;
......@@ -2077,9 +2113,8 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb,
int ifindex;
int err;
err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
devconf_ipv4_policy, extack);
if (err < 0)
err = inet_netconf_valid_get_req(in_skb, nlh, tb, extack);
if (err)
goto errout;
err = -EINVAL;
......
......@@ -2467,6 +2467,61 @@ static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
rtnl_set_sk_err(net, RTNLGRP_IPV4_MROUTE_R, -ENOBUFS);
}
static int ipmr_rtm_valid_getroute_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
struct rtmsg *rtm;
int i, err;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
NL_SET_ERR_MSG(extack, "ipv4: Invalid header for multicast route get request");
return -EINVAL;
}
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_ipv4_policy, extack);
rtm = nlmsg_data(nlh);
if ((rtm->rtm_src_len && rtm->rtm_src_len != 32) ||
(rtm->rtm_dst_len && rtm->rtm_dst_len != 32) ||
rtm->rtm_tos || rtm->rtm_table || rtm->rtm_protocol ||
rtm->rtm_scope || rtm->rtm_type || rtm->rtm_flags) {
NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for multicast route get request");
return -EINVAL;
}
err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_ipv4_policy, extack);
if (err)
return err;
if ((tb[RTA_SRC] && !rtm->rtm_src_len) ||
(tb[RTA_DST] && !rtm->rtm_dst_len)) {
NL_SET_ERR_MSG(extack, "ipv4: rtm_src_len and rtm_dst_len must be 32 for IPv4");
return -EINVAL;
}
for (i = 0; i <= RTA_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case RTA_SRC:
case RTA_DST:
case RTA_TABLE:
break;
default:
NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in multicast route get request");
return -EINVAL;
}
}
return 0;
}
static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
......@@ -2475,18 +2530,14 @@ static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
struct sk_buff *skb = NULL;
struct mfc_cache *cache;
struct mr_table *mrt;
struct rtmsg *rtm;
__be32 src, grp;
u32 tableid;
int err;
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_ipv4_policy, extack);
err = ipmr_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
if (err < 0)
goto errout;
rtm = nlmsg_data(nlh);
src = tb[RTA_SRC] ? nla_get_in_addr(tb[RTA_SRC]) : 0;
grp = tb[RTA_DST] ? nla_get_in_addr(tb[RTA_DST]) : 0;
tableid = tb[RTA_TABLE] ? nla_get_u32(tb[RTA_TABLE]) : 0;
......
......@@ -2763,6 +2763,75 @@ static struct sk_buff *inet_rtm_getroute_build_skb(__be32 src, __be32 dst,
return skb;
}
static int inet_rtm_valid_getroute_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
struct rtmsg *rtm;
int i, err;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
NL_SET_ERR_MSG(extack,
"ipv4: Invalid header for route get request");
return -EINVAL;
}
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_ipv4_policy, extack);
rtm = nlmsg_data(nlh);
if ((rtm->rtm_src_len && rtm->rtm_src_len != 32) ||
(rtm->rtm_dst_len && rtm->rtm_dst_len != 32) ||
rtm->rtm_table || rtm->rtm_protocol ||
rtm->rtm_scope || rtm->rtm_type) {
NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for route get request");
return -EINVAL;
}
if (rtm->rtm_flags & ~(RTM_F_NOTIFY |
RTM_F_LOOKUP_TABLE |
RTM_F_FIB_MATCH)) {
NL_SET_ERR_MSG(extack, "ipv4: Unsupported rtm_flags for route get request");
return -EINVAL;
}
err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_ipv4_policy, extack);
if (err)
return err;
if ((tb[RTA_SRC] && !rtm->rtm_src_len) ||
(tb[RTA_DST] && !rtm->rtm_dst_len)) {
NL_SET_ERR_MSG(extack, "ipv4: rtm_src_len and rtm_dst_len must be 32 for IPv4");
return -EINVAL;
}
for (i = 0; i <= RTA_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case RTA_IIF:
case RTA_OIF:
case RTA_SRC:
case RTA_DST:
case RTA_IP_PROTO:
case RTA_SPORT:
case RTA_DPORT:
case RTA_MARK:
case RTA_UID:
break;
default:
NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in route get request");
return -EINVAL;
}
}
return 0;
}
static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
......@@ -2783,8 +2852,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
int err;
int mark;
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy,
extack);
err = inet_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
if (err < 0)
return err;
......
......@@ -597,6 +597,43 @@ static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = {
[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) },
};
static int inet6_netconf_valid_get_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
int i, err;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) {
NL_SET_ERR_MSG_MOD(extack, "Invalid header for netconf get request");
return -EINVAL;
}
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(struct netconfmsg), tb,
NETCONFA_MAX, devconf_ipv6_policy, extack);
err = nlmsg_parse_strict(nlh, sizeof(struct netconfmsg), tb,
NETCONFA_MAX, devconf_ipv6_policy, extack);
if (err)
return err;
for (i = 0; i <= NETCONFA_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case NETCONFA_IFINDEX:
break;
default:
NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in netconf get request");
return -EINVAL;
}
}
return 0;
}
static int inet6_netconf_get_devconf(struct sk_buff *in_skb,
struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
......@@ -605,14 +642,12 @@ static int inet6_netconf_get_devconf(struct sk_buff *in_skb,
struct nlattr *tb[NETCONFA_MAX+1];
struct inet6_dev *in6_dev = NULL;
struct net_device *dev = NULL;
struct netconfmsg *ncm;
struct sk_buff *skb;
struct ipv6_devconf *devconf;
int ifindex;
int err;
err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
devconf_ipv6_policy, extack);
err = inet6_netconf_valid_get_req(in_skb, nlh, tb, extack);
if (err < 0)
return err;
......@@ -5179,6 +5214,52 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb)
return inet6_dump_addr(skb, cb, type);
}
static int inet6_rtm_valid_getaddr_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
struct ifaddrmsg *ifm;
int i, err;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) {
NL_SET_ERR_MSG_MOD(extack, "Invalid header for get address request");
return -EINVAL;
}
ifm = nlmsg_data(nlh);
if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) {
NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get address request");
return -EINVAL;
}
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX,
ifa_ipv6_policy, extack);
err = nlmsg_parse_strict(nlh, sizeof(*ifm), tb, IFA_MAX,
ifa_ipv6_policy, extack);
if (err)
return err;
for (i = 0; i <= IFA_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case IFA_TARGET_NETNSID:
case IFA_ADDRESS:
case IFA_LOCAL:
break;
default:
NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get address request");
return -EINVAL;
}
}
return 0;
}
static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
......@@ -5199,8 +5280,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh,
struct sk_buff *skb;
int err;
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy,
extack);
err = inet6_rtm_valid_getaddr_req(in_skb, nlh, tb, extack);
if (err < 0)
return err;
......
......@@ -523,6 +523,50 @@ static inline int ip6addrlbl_msgsize(void)
+ nla_total_size(4); /* IFAL_LABEL */
}
static int ip6addrlbl_valid_get_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
struct ifaddrlblmsg *ifal;
int i, err;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifal))) {
NL_SET_ERR_MSG_MOD(extack, "Invalid header for addrlabel get request");
return -EINVAL;
}
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX,
ifal_policy, extack);
ifal = nlmsg_data(nlh);
if (ifal->__ifal_reserved || ifal->ifal_flags || ifal->ifal_seq) {
NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for addrlabel get request");
return -EINVAL;
}
err = nlmsg_parse_strict(nlh, sizeof(*ifal), tb, IFAL_MAX,
ifal_policy, extack);
if (err)
return err;
for (i = 0; i <= IFAL_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case IFAL_ADDRESS:
break;
default:
NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in addrlabel get request");
return -EINVAL;
}
}
return 0;
}
static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
......@@ -535,8 +579,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
struct ip6addrlbl_entry *p;
struct sk_buff *skb;
err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy,
extack);
err = ip6addrlbl_valid_get_req(in_skb, nlh, tb, extack);
if (err < 0)
return err;
......
......@@ -4822,6 +4822,73 @@ int rt6_dump_route(struct fib6_info *rt, void *p_arg)
arg->cb->nlh->nlmsg_seq, flags);
}
static int inet6_rtm_valid_getroute_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
struct rtmsg *rtm;
int i, err;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
NL_SET_ERR_MSG_MOD(extack,
"Invalid header for get route request");
return -EINVAL;
}
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_ipv6_policy, extack);
rtm = nlmsg_data(nlh);
if ((rtm->rtm_src_len && rtm->rtm_src_len != 128) ||
(rtm->rtm_dst_len && rtm->rtm_dst_len != 128) ||
rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope ||
rtm->rtm_type) {
NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get route request");
return -EINVAL;
}
if (rtm->rtm_flags & ~RTM_F_FIB_MATCH) {
NL_SET_ERR_MSG_MOD(extack,
"Invalid flags for get route request");
return -EINVAL;
}
err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_ipv6_policy, extack);
if (err)
return err;
if ((tb[RTA_SRC] && !rtm->rtm_src_len) ||
(tb[RTA_DST] && !rtm->rtm_dst_len)) {
NL_SET_ERR_MSG_MOD(extack, "rtm_src_len and rtm_dst_len must be 128 for IPv6");
return -EINVAL;
}
for (i = 0; i <= RTA_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case RTA_SRC:
case RTA_DST:
case RTA_IIF:
case RTA_OIF:
case RTA_MARK:
case RTA_UID:
case RTA_SPORT:
case RTA_DPORT:
case RTA_IP_PROTO:
break;
default:
NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request");
return -EINVAL;
}
}
return 0;
}
static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
......@@ -4836,8 +4903,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
struct flowi6 fl6 = {};
bool fibmatch;
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
extack);
err = inet6_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
if (err < 0)
goto errout;
......
......@@ -1209,21 +1209,57 @@ static const struct nla_policy devconf_mpls_policy[NETCONFA_MAX + 1] = {
[NETCONFA_IFINDEX] = { .len = sizeof(int) },
};
static int mpls_netconf_valid_get_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
int i, err;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) {
NL_SET_ERR_MSG_MOD(extack,
"Invalid header for netconf get request");
return -EINVAL;
}
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(struct netconfmsg), tb,
NETCONFA_MAX, devconf_mpls_policy, extack);
err = nlmsg_parse_strict(nlh, sizeof(struct netconfmsg), tb,
NETCONFA_MAX, devconf_mpls_policy, extack);
if (err)
return err;
for (i = 0; i <= NETCONFA_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case NETCONFA_IFINDEX:
break;
default:
NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in netconf get request");
return -EINVAL;
}
}
return 0;
}
static int mpls_netconf_get_devconf(struct sk_buff *in_skb,
struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(in_skb->sk);
struct nlattr *tb[NETCONFA_MAX + 1];
struct netconfmsg *ncm;
struct net_device *dev;
struct mpls_dev *mdev;
struct sk_buff *skb;
int ifindex;
int err;
err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
devconf_mpls_policy, extack);
err = mpls_netconf_valid_get_req(in_skb, nlh, tb, extack);
if (err < 0)
goto errout;
......@@ -2236,6 +2272,64 @@ static void rtmsg_lfib(int event, u32 label, struct mpls_route *rt,
rtnl_set_sk_err(net, RTNLGRP_MPLS_ROUTE, err);
}
static int mpls_valid_getroute_req(struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{
struct rtmsg *rtm;
int i, err;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
NL_SET_ERR_MSG_MOD(extack,
"Invalid header for get route request");
return -EINVAL;
}
if (!netlink_strict_get_check(skb))
return nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_mpls_policy, extack);
rtm = nlmsg_data(nlh);
if ((rtm->rtm_dst_len && rtm->rtm_dst_len != 20) ||
rtm->rtm_src_len || rtm->rtm_tos || rtm->rtm_table ||
rtm->rtm_protocol || rtm->rtm_scope || rtm->rtm_type) {
NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get route request");
return -EINVAL;
}
if (rtm->rtm_flags & ~RTM_F_FIB_MATCH) {
NL_SET_ERR_MSG_MOD(extack,
"Invalid flags for get route request");
return -EINVAL;
}
err = nlmsg_parse_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_mpls_policy, extack);
if (err)
return err;
if ((tb[RTA_DST] || tb[RTA_NEWDST]) && !rtm->rtm_dst_len) {
NL_SET_ERR_MSG_MOD(extack, "rtm_dst_len must be 20 for MPLS");
return -EINVAL;
}
for (i = 0; i <= RTA_MAX; i++) {
if (!tb[i])
continue;
switch (i) {
case RTA_DST:
case RTA_NEWDST:
break;
default:
NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request");
return -EINVAL;
}
}
return 0;
}
static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
struct netlink_ext_ack *extack)
{
......@@ -2255,8 +2349,7 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
u8 n_labels;
int err;
err = nlmsg_parse(in_nlh, sizeof(*rtm), tb, RTA_MAX,
rtm_mpls_policy, extack);
err = mpls_valid_getroute_req(in_skb, in_nlh, tb, extack);
if (err < 0)
goto errout;
......
......@@ -1371,6 +1371,14 @@ int netlink_has_listeners(struct sock *sk, unsigned int group)
}
EXPORT_SYMBOL_GPL(netlink_has_listeners);
bool netlink_strict_get_check(struct sk_buff *skb)
{
const struct netlink_sock *nlk = nlk_sk(NETLINK_CB(skb).sk);
return nlk->flags & NETLINK_F_STRICT_CHK;
}
EXPORT_SYMBOL_GPL(netlink_strict_get_check);
static int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
{
struct netlink_sock *nlk = nlk_sk(sk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment