hc
2024-05-11 04dd17822334871b23ea2862f7798fb0e0007777
kernel/net/ipv4/metrics.c
....@@ -1,12 +1,15 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 #include <linux/netlink.h>
3
+#include <linux/nospec.h>
24 #include <linux/rtnetlink.h>
35 #include <linux/types.h>
46 #include <net/ip.h>
57 #include <net/net_namespace.h>
68 #include <net/tcp.h>
79
8
-int ip_metrics_convert(struct net *net, struct nlattr *fc_mx, int fc_mx_len,
9
- u32 *metrics)
10
+static int ip_metrics_convert(struct net *net, struct nlattr *fc_mx,
11
+ int fc_mx_len, u32 *metrics,
12
+ struct netlink_ext_ack *extack)
1013 {
1114 bool ecn_ca = false;
1215 struct nlattr *nla;
....@@ -21,19 +24,27 @@
2124
2225 if (!type)
2326 continue;
24
- if (type > RTAX_MAX)
27
+ if (type > RTAX_MAX) {
28
+ NL_SET_ERR_MSG(extack, "Invalid metric type");
2529 return -EINVAL;
30
+ }
2631
32
+ type = array_index_nospec(type, RTAX_MAX + 1);
2733 if (type == RTAX_CC_ALGO) {
2834 char tmp[TCP_CA_NAME_MAX];
2935
3036 nla_strlcpy(tmp, nla, sizeof(tmp));
3137 val = tcp_ca_get_key_by_name(net, tmp, &ecn_ca);
32
- if (val == TCP_CA_UNSPEC)
38
+ if (val == TCP_CA_UNSPEC) {
39
+ NL_SET_ERR_MSG(extack, "Unknown tcp congestion algorithm");
3340 return -EINVAL;
41
+ }
3442 } else {
35
- if (nla_len(nla) != sizeof(u32))
43
+ if (nla_len(nla) != sizeof(u32)) {
44
+ NL_SET_ERR_MSG_ATTR(extack, nla,
45
+ "Invalid attribute in metrics");
3646 return -EINVAL;
47
+ }
3748 val = nla_get_u32(nla);
3849 }
3950 if (type == RTAX_ADVMSS && val > 65535 - 40)
....@@ -42,8 +53,10 @@
4253 val = 65535 - 15;
4354 if (type == RTAX_HOPLIMIT && val > 255)
4455 val = 255;
45
- if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
56
+ if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK)) {
57
+ NL_SET_ERR_MSG(extack, "Unknown flag set in feature mask in metrics attribute");
4658 return -EINVAL;
59
+ }
4760 metrics[type - 1] = val;
4861 }
4962
....@@ -52,4 +65,30 @@
5265
5366 return 0;
5467 }
55
-EXPORT_SYMBOL_GPL(ip_metrics_convert);
68
+
69
+struct dst_metrics *ip_fib_metrics_init(struct net *net, struct nlattr *fc_mx,
70
+ int fc_mx_len,
71
+ struct netlink_ext_ack *extack)
72
+{
73
+ struct dst_metrics *fib_metrics;
74
+ int err;
75
+
76
+ if (!fc_mx)
77
+ return (struct dst_metrics *)&dst_default_metrics;
78
+
79
+ fib_metrics = kzalloc(sizeof(*fib_metrics), GFP_KERNEL);
80
+ if (unlikely(!fib_metrics))
81
+ return ERR_PTR(-ENOMEM);
82
+
83
+ err = ip_metrics_convert(net, fc_mx, fc_mx_len, fib_metrics->metrics,
84
+ extack);
85
+ if (!err) {
86
+ refcount_set(&fib_metrics->refcnt, 1);
87
+ } else {
88
+ kfree(fib_metrics);
89
+ fib_metrics = ERR_PTR(err);
90
+ }
91
+
92
+ return fib_metrics;
93
+}
94
+EXPORT_SYMBOL_GPL(ip_fib_metrics_init);