diff options
author | Kees Cook <keescook@chromium.org> | 2018-05-30 18:20:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-05-31 22:48:46 -0400 |
commit | ccf8dbcd062a930e64741c939ca784d15316aa0c (patch) | |
tree | 2ee1f0523cb121c01d5bc082875c1393ce8691dd | |
parent | 7bb8c9969d919517fc379cacebd8fa93704173db (diff) |
rtnetlink: Remove VLA usage
In the quest to remove all stack VLA usage from the kernel[1], this
allocates the maximum size expected for all possible types and adds
sanity-checks at both registration and usage to make sure nothing gets
out of sync. This matches the proposed VLA solution for nfnetlink[2]. The
values chosen here were based on finding assignments for .maxtype and
.slave_maxtype and manually counting the enums:
slave_maxtype (max 33):
IFLA_BRPORT_MAX 33
IFLA_BOND_SLAVE_MAX 9
maxtype (max 45):
IFLA_BOND_MAX 28
IFLA_BR_MAX 45
__IFLA_CAIF_HSI_MAX 8
IFLA_CAIF_MAX 4
IFLA_CAN_MAX 16
IFLA_GENEVE_MAX 12
IFLA_GRE_MAX 25
IFLA_GTP_MAX 5
IFLA_HSR_MAX 7
IFLA_IPOIB_MAX 4
IFLA_IPTUN_MAX 21
IFLA_IPVLAN_MAX 3
IFLA_MACSEC_MAX 15
IFLA_MACVLAN_MAX 7
IFLA_PPP_MAX 2
__IFLA_RMNET_MAX 4
IFLA_VLAN_MAX 6
IFLA_VRF_MAX 2
IFLA_VTI_MAX 7
IFLA_VXLAN_MAX 28
VETH_INFO_MAX 2
VXCAN_INFO_MAX 2
This additionally changes maxtype and slave_maxtype fields to unsigned,
since they're only ever using positive values.
[1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com
[2] https://patchwork.kernel.org/patch/10439647/
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/rtnetlink.h | 4 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 18 |
2 files changed, 18 insertions, 4 deletions
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 14b6b3af8918..0bbaa5488423 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h | |||
@@ -64,7 +64,7 @@ struct rtnl_link_ops { | |||
64 | size_t priv_size; | 64 | size_t priv_size; |
65 | void (*setup)(struct net_device *dev); | 65 | void (*setup)(struct net_device *dev); |
66 | 66 | ||
67 | int maxtype; | 67 | unsigned int maxtype; |
68 | const struct nla_policy *policy; | 68 | const struct nla_policy *policy; |
69 | int (*validate)(struct nlattr *tb[], | 69 | int (*validate)(struct nlattr *tb[], |
70 | struct nlattr *data[], | 70 | struct nlattr *data[], |
@@ -92,7 +92,7 @@ struct rtnl_link_ops { | |||
92 | unsigned int (*get_num_tx_queues)(void); | 92 | unsigned int (*get_num_tx_queues)(void); |
93 | unsigned int (*get_num_rx_queues)(void); | 93 | unsigned int (*get_num_rx_queues)(void); |
94 | 94 | ||
95 | int slave_maxtype; | 95 | unsigned int slave_maxtype; |
96 | const struct nla_policy *slave_policy; | 96 | const struct nla_policy *slave_policy; |
97 | int (*slave_changelink)(struct net_device *dev, | 97 | int (*slave_changelink)(struct net_device *dev, |
98 | struct net_device *slave_dev, | 98 | struct net_device *slave_dev, |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 80802546c279..8ca49a0e13fb 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -59,6 +59,9 @@ | |||
59 | #include <net/rtnetlink.h> | 59 | #include <net/rtnetlink.h> |
60 | #include <net/net_namespace.h> | 60 | #include <net/net_namespace.h> |
61 | 61 | ||
62 | #define RTNL_MAX_TYPE 48 | ||
63 | #define RTNL_SLAVE_MAX_TYPE 36 | ||
64 | |||
62 | struct rtnl_link { | 65 | struct rtnl_link { |
63 | rtnl_doit_func doit; | 66 | rtnl_doit_func doit; |
64 | rtnl_dumpit_func dumpit; | 67 | rtnl_dumpit_func dumpit; |
@@ -389,6 +392,11 @@ int rtnl_link_register(struct rtnl_link_ops *ops) | |||
389 | { | 392 | { |
390 | int err; | 393 | int err; |
391 | 394 | ||
395 | /* Sanity-check max sizes to avoid stack buffer overflow. */ | ||
396 | if (WARN_ON(ops->maxtype > RTNL_MAX_TYPE || | ||
397 | ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE)) | ||
398 | return -EINVAL; | ||
399 | |||
392 | rtnl_lock(); | 400 | rtnl_lock(); |
393 | err = __rtnl_link_register(ops); | 401 | err = __rtnl_link_register(ops); |
394 | rtnl_unlock(); | 402 | rtnl_unlock(); |
@@ -2902,13 +2910,16 @@ replay: | |||
2902 | } | 2910 | } |
2903 | 2911 | ||
2904 | if (1) { | 2912 | if (1) { |
2905 | struct nlattr *attr[ops ? ops->maxtype + 1 : 1]; | 2913 | struct nlattr *attr[RTNL_MAX_TYPE + 1]; |
2906 | struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 1]; | 2914 | struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1]; |
2907 | struct nlattr **data = NULL; | 2915 | struct nlattr **data = NULL; |
2908 | struct nlattr **slave_data = NULL; | 2916 | struct nlattr **slave_data = NULL; |
2909 | struct net *dest_net, *link_net = NULL; | 2917 | struct net *dest_net, *link_net = NULL; |
2910 | 2918 | ||
2911 | if (ops) { | 2919 | if (ops) { |
2920 | if (ops->maxtype > RTNL_MAX_TYPE) | ||
2921 | return -EINVAL; | ||
2922 | |||
2912 | if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { | 2923 | if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { |
2913 | err = nla_parse_nested(attr, ops->maxtype, | 2924 | err = nla_parse_nested(attr, ops->maxtype, |
2914 | linkinfo[IFLA_INFO_DATA], | 2925 | linkinfo[IFLA_INFO_DATA], |
@@ -2925,6 +2936,9 @@ replay: | |||
2925 | } | 2936 | } |
2926 | 2937 | ||
2927 | if (m_ops) { | 2938 | if (m_ops) { |
2939 | if (ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE) | ||
2940 | return -EINVAL; | ||
2941 | |||
2928 | if (m_ops->slave_maxtype && | 2942 | if (m_ops->slave_maxtype && |
2929 | linkinfo[IFLA_INFO_SLAVE_DATA]) { | 2943 | linkinfo[IFLA_INFO_SLAVE_DATA]) { |
2930 | err = nla_parse_nested(slave_attr, | 2944 | err = nla_parse_nested(slave_attr, |