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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e266afa9c7
@ -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 @@ nla_put_failure:
|
||||
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 @@ errout:
|
||||
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 @@ errout:
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user