hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/net/xfrm/xfrm_compat.c
....@@ -5,6 +5,7 @@
55 * Based on code and translator idea by: Florian Westphal <fw@strlen.de>
66 */
77 #include <linux/compat.h>
8
+#include <linux/nospec.h>
89 #include <linux/xfrm.h>
910 #include <net/xfrm.h>
1011
....@@ -107,7 +108,7 @@
107108 [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) },
108109 [XFRMA_ENCAP] = { .len = sizeof(struct xfrm_encap_tmpl) },
109110 [XFRMA_TMPL] = { .len = sizeof(struct xfrm_user_tmpl) },
110
- [XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_sec_ctx) },
111
+ [XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_user_sec_ctx) },
111112 [XFRMA_LTIME_VAL] = { .len = sizeof(struct xfrm_lifetime_cur) },
112113 [XFRMA_REPLAY_VAL] = { .len = sizeof(struct xfrm_replay_state) },
113114 [XFRMA_REPLAY_THRESH] = { .type = NLA_U32 },
....@@ -216,7 +217,7 @@
216217 case XFRM_MSG_GETSADINFO:
217218 case XFRM_MSG_GETSPDINFO:
218219 default:
219
- WARN_ONCE(1, "unsupported nlmsg_type %d", nlh_src->nlmsg_type);
220
+ pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type);
220221 return ERR_PTR(-EOPNOTSUPP);
221222 }
222223
....@@ -234,6 +235,7 @@
234235 case XFRMA_PAD:
235236 /* Ignore */
236237 return 0;
238
+ case XFRMA_UNSPEC:
237239 case XFRMA_ALG_AUTH:
238240 case XFRMA_ALG_CRYPT:
239241 case XFRMA_ALG_COMP:
....@@ -276,7 +278,7 @@
276278 return xfrm_nla_cpy(dst, src, nla_len(src));
277279 default:
278280 BUILD_BUG_ON(XFRMA_MAX != XFRMA_IF_ID);
279
- WARN_ONCE(1, "unsupported nla_type %d", src->nla_type);
281
+ pr_warn_once("unsupported nla_type %d\n", src->nla_type);
280282 return -EOPNOTSUPP;
281283 }
282284 }
....@@ -297,8 +299,16 @@
297299 len = nlmsg_attrlen(nlh_src, xfrm_msg_min[type]);
298300
299301 nla_for_each_attr(nla, attrs, len, remaining) {
300
- int err = xfrm_xlate64_attr(dst, nla);
302
+ int err;
301303
304
+ switch (nlh_src->nlmsg_type) {
305
+ case XFRM_MSG_NEWSPDINFO:
306
+ err = xfrm_nla_cpy(dst, nla, nla_len(nla));
307
+ break;
308
+ default:
309
+ err = xfrm_xlate64_attr(dst, nla);
310
+ break;
311
+ }
302312 if (err)
303313 return err;
304314 }
....@@ -314,8 +324,10 @@
314324 struct sk_buff *new = NULL;
315325 int err;
316326
317
- if (WARN_ON_ONCE(type >= ARRAY_SIZE(xfrm_msg_min)))
327
+ if (type >= ARRAY_SIZE(xfrm_msg_min)) {
328
+ pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type);
318329 return -EOPNOTSUPP;
330
+ }
319331
320332 if (skb_shinfo(skb)->frag_list == NULL) {
321333 new = alloc_skb(skb->len + skb_tailroom(skb), GFP_ATOMIC);
....@@ -338,7 +350,8 @@
338350
339351 /* Calculates len of translated 64-bit message. */
340352 static size_t xfrm_user_rcv_calculate_len64(const struct nlmsghdr *src,
341
- struct nlattr *attrs[XFRMA_MAX+1])
353
+ struct nlattr *attrs[XFRMA_MAX + 1],
354
+ int maxtype)
342355 {
343356 size_t len = nlmsg_len(src);
344357
....@@ -355,9 +368,19 @@
355368 case XFRM_MSG_POLEXPIRE:
356369 len += 8;
357370 break;
371
+ case XFRM_MSG_NEWSPDINFO:
372
+ /* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */
373
+ return len;
358374 default:
359375 break;
360376 }
377
+
378
+ /* Unexpected for anything, but XFRM_MSG_NEWSPDINFO, please
379
+ * correct both 64=>32-bit and 32=>64-bit translators to copy
380
+ * new attributes.
381
+ */
382
+ if (WARN_ON_ONCE(maxtype))
383
+ return len;
361384
362385 if (attrs[XFRMA_SA])
363386 len += 4;
....@@ -377,6 +400,10 @@
377400 struct nlmsghdr *nlmsg = dst;
378401 struct nlattr *nla;
379402
403
+ /* xfrm_user_rcv_msg_compat() relies on fact that 32-bit messages
404
+ * have the same len or shorted than 64-bit ones.
405
+ * 32-bit translation that is bigger than 64-bit original is unexpected.
406
+ */
380407 if (WARN_ON_ONCE(copy_len > payload))
381408 copy_len = payload;
382409
....@@ -387,7 +414,7 @@
387414
388415 memcpy(nla, src, nla_attr_size(copy_len));
389416 nla->nla_len = nla_attr_size(payload);
390
- *pos += nla_attr_size(payload);
417
+ *pos += nla_attr_size(copy_len);
391418 nlmsg->nlmsg_len += nla->nla_len;
392419
393420 memset(dst + *pos, 0, payload - copy_len);
....@@ -409,6 +436,7 @@
409436 NL_SET_ERR_MSG(extack, "Bad attribute");
410437 return -EOPNOTSUPP;
411438 }
439
+ type = array_index_nospec(type, XFRMA_MAX + 1);
412440 if (nla_len(nla) < compat_policy[type].len) {
413441 NL_SET_ERR_MSG(extack, "Attribute bad length");
414442 return -EOPNOTSUPP;
....@@ -433,7 +461,8 @@
433461
434462 static int xfrm_xlate32(struct nlmsghdr *dst, const struct nlmsghdr *src,
435463 struct nlattr *attrs[XFRMA_MAX+1],
436
- size_t size, u8 type, struct netlink_ext_ack *extack)
464
+ size_t size, u8 type, int maxtype,
465
+ struct netlink_ext_ack *extack)
437466 {
438467 size_t pos;
439468 int i;
....@@ -513,6 +542,25 @@
513542 }
514543 pos = dst->nlmsg_len;
515544
545
+ if (maxtype) {
546
+ /* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */
547
+ WARN_ON_ONCE(src->nlmsg_type != XFRM_MSG_NEWSPDINFO);
548
+
549
+ for (i = 1; i <= maxtype; i++) {
550
+ int err;
551
+
552
+ if (!attrs[i])
553
+ continue;
554
+
555
+ /* just copy - no need for translation */
556
+ err = xfrm_attr_cpy32(dst, &pos, attrs[i], size,
557
+ nla_len(attrs[i]), nla_len(attrs[i]));
558
+ if (err)
559
+ return err;
560
+ }
561
+ return 0;
562
+ }
563
+
516564 for (i = 1; i < XFRMA_MAX + 1; i++) {
517565 int err;
518566
....@@ -552,22 +600,22 @@
552600 (h32->nlmsg_flags & NLM_F_DUMP))
553601 return NULL;
554602
555
- err = nlmsg_parse(h32, compat_msg_min[type], attrs,
603
+ err = nlmsg_parse_deprecated(h32, compat_msg_min[type], attrs,
556604 maxtype ? : XFRMA_MAX, policy ? : compat_policy, extack);
557605 if (err < 0)
558606 return ERR_PTR(err);
559607
560
- len = xfrm_user_rcv_calculate_len64(h32, attrs);
608
+ len = xfrm_user_rcv_calculate_len64(h32, attrs, maxtype);
561609 /* The message doesn't need translation */
562610 if (len == nlmsg_len(h32))
563611 return NULL;
564612
565613 len += NLMSG_HDRLEN;
566
- h64 = kvmalloc(len, GFP_KERNEL | __GFP_ZERO);
614
+ h64 = kvmalloc(len, GFP_KERNEL);
567615 if (!h64)
568616 return ERR_PTR(-ENOMEM);
569617
570
- err = xfrm_xlate32(h64, h32, attrs, len, type, extack);
618
+ err = xfrm_xlate32(h64, h32, attrs, len, type, maxtype, extack);
571619 if (err < 0) {
572620 kvfree(h64);
573621 return ERR_PTR(err);
....@@ -585,7 +633,7 @@
585633 if (optlen < sizeof(*p))
586634 return -EINVAL;
587635
588
- data64 = kmalloc(optlen + 4, GFP_USER | __GFP_NOWARN);
636
+ data64 = kmalloc_track_caller(optlen + 4, GFP_USER | __GFP_NOWARN);
589637 if (!data64)
590638 return -ENOMEM;
591639