Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'ipsec-next-2024-05-03' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next

Steffen Klassert says:

====================
pull request (net-next): ipsec-next 2024-05-03

1) Remove Obsolete UDP_ENCAP_ESPINUDP_NON_IKE Support.
This was defined by an early version of an IETF draft
that did not make it to a standard.

2) Introduce direction attribute for xfrm states.
xfrm states have a direction, a stsate can be used
either for input or output packet processing.
Add a direction to xfrm states to make it clear
for what a xfrm state is used.

* tag 'ipsec-next-2024-05-03' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next:
xfrm: Restrict SA direction attribute to specific netlink message types
xfrm: Add dir validation to "in" data path lookup
xfrm: Add dir validation to "out" data path lookup
xfrm: Add Direction to the SA in or out
udpencap: Remove Obsolete UDP_ENCAP_ESPINUDP_NON_IKE Support
====================

Link: https://lore.kernel.org/r/20240503082732.2835810-1-steffen.klassert@secunet.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+219 -62
+6
Documentation/networking/xfrm_proc.rst
··· 73 73 XfrmFwdHdrError: 74 74 Forward routing of a packet is not allowed 75 75 76 + XfrmInStateDirError: 77 + State direction mismatch (lookup found an output state on the input path, expected input or no direction) 78 + 76 79 Outbound errors 77 80 ~~~~~~~~~~~~~~~ 78 81 XfrmOutError: ··· 114 111 115 112 XfrmOutStateInvalid: 116 113 State is invalid, perhaps expired 114 + 115 + XfrmOutStateDirError: 116 + State direction mismatch (lookup found an input state on the output path, expected output or no direction)
+1
include/net/xfrm.h
··· 291 291 /* Private data of this transformer, format is opaque, 292 292 * interpreted by xfrm_type methods. */ 293 293 void *data; 294 + u8 dir; 294 295 }; 295 296 296 297 static inline struct net *xs_net(struct xfrm_state *x)
+2
include/uapi/linux/snmp.h
··· 337 337 LINUX_MIB_XFRMFWDHDRERROR, /* XfrmFwdHdrError*/ 338 338 LINUX_MIB_XFRMOUTSTATEINVALID, /* XfrmOutStateInvalid */ 339 339 LINUX_MIB_XFRMACQUIREERROR, /* XfrmAcquireError */ 340 + LINUX_MIB_XFRMOUTSTATEDIRERROR, /* XfrmOutStateDirError */ 341 + LINUX_MIB_XFRMINSTATEDIRERROR, /* XfrmInStateDirError */ 340 342 __LINUX_MIB_XFRMMAX 341 343 }; 342 344
+1 -1
include/uapi/linux/udp.h
··· 36 36 #define UDP_GRO 104 /* This socket can receive UDP GRO packets */ 37 37 38 38 /* UDP encapsulation types */ 39 - #define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */ 39 + #define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* unused draft-ietf-ipsec-nat-t-ike-00/01 */ 40 40 #define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-06 */ 41 41 #define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */ 42 42 #define UDP_ENCAP_GTP0 4 /* GSM TS 09.60 */
+6
include/uapi/linux/xfrm.h
··· 141 141 XFRM_POLICY_MAX = 3 142 142 }; 143 143 144 + enum xfrm_sa_dir { 145 + XFRM_SA_DIR_IN = 1, 146 + XFRM_SA_DIR_OUT = 2 147 + }; 148 + 144 149 enum { 145 150 XFRM_SHARE_ANY, /* No limitations */ 146 151 XFRM_SHARE_SESSION, /* For this session only */ ··· 320 315 XFRMA_SET_MARK_MASK, /* __u32 */ 321 316 XFRMA_IF_ID, /* __u32 */ 322 317 XFRMA_MTIMER_THRESH, /* __u32 in seconds for input SA */ 318 + XFRMA_SA_DIR, /* __u8 */ 323 319 __XFRMA_MAX 324 320 325 321 #define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */
-12
net/ipv4/esp4.c
··· 348 348 __be16 dport) 349 349 { 350 350 struct udphdr *uh; 351 - __be32 *udpdata32; 352 351 unsigned int len; 353 352 354 353 len = skb->len + esp->tailen - skb_transport_offset(skb); ··· 361 362 uh->check = 0; 362 363 363 364 *skb_mac_header(skb) = IPPROTO_UDP; 364 - 365 - if (encap_type == UDP_ENCAP_ESPINUDP_NON_IKE) { 366 - udpdata32 = (__be32 *)(uh + 1); 367 - udpdata32[0] = udpdata32[1] = 0; 368 - return (struct ip_esp_hdr *)(udpdata32 + 2); 369 - } 370 365 371 366 return (struct ip_esp_hdr *)(uh + 1); 372 367 } ··· 417 424 switch (encap_type) { 418 425 default: 419 426 case UDP_ENCAP_ESPINUDP: 420 - case UDP_ENCAP_ESPINUDP_NON_IKE: 421 427 esph = esp_output_udp_encap(skb, encap_type, esp, sport, dport); 422 428 break; 423 429 case TCP_ENCAP_ESPINTCP: ··· 768 776 source = th->source; 769 777 break; 770 778 case UDP_ENCAP_ESPINUDP: 771 - case UDP_ENCAP_ESPINUDP_NON_IKE: 772 779 source = uh->source; 773 780 break; 774 781 default: ··· 1170 1179 goto error; 1171 1180 case UDP_ENCAP_ESPINUDP: 1172 1181 x->props.header_len += sizeof(struct udphdr); 1173 - break; 1174 - case UDP_ENCAP_ESPINUDP_NON_IKE: 1175 - x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32); 1176 1182 break; 1177 1183 #ifdef CONFIG_INET_ESPINTCP 1178 1184 case TCP_ENCAP_ESPINTCP:
-2
net/ipv4/udp.c
··· 2712 2712 #ifdef CONFIG_XFRM 2713 2713 case UDP_ENCAP_ESPINUDP: 2714 2714 set_xfrm_gro_udp_encap_rcv(val, sk->sk_family, sk); 2715 - fallthrough; 2716 - case UDP_ENCAP_ESPINUDP_NON_IKE: 2717 2715 #if IS_ENABLED(CONFIG_IPV6) 2718 2716 if (sk->sk_family == AF_INET6) 2719 2717 WRITE_ONCE(up->encap_rcv,
-13
net/ipv4/xfrm4_input.c
··· 113 113 /* Must be an IKE packet.. pass it through */ 114 114 return 1; 115 115 break; 116 - case UDP_ENCAP_ESPINUDP_NON_IKE: 117 - /* Check if this is a keepalive packet. If so, eat it. */ 118 - if (len == 1 && udpdata[0] == 0xff) { 119 - return -EINVAL; 120 - } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) && 121 - udpdata32[0] == 0 && udpdata32[1] == 0) { 122 - 123 - /* ESP Packet with Non-IKE marker */ 124 - len = sizeof(struct udphdr) + 2 * sizeof(u32); 125 - } else 126 - /* Must be an IKE packet.. pass it through */ 127 - return 1; 128 - break; 129 116 } 130 117 131 118 /* At this point we are sure that this is an ESPinUDP packet,
-12
net/ipv6/esp6.c
··· 384 384 __be16 dport) 385 385 { 386 386 struct udphdr *uh; 387 - __be32 *udpdata32; 388 387 unsigned int len; 389 388 390 389 len = skb->len + esp->tailen - skb_transport_offset(skb); ··· 397 398 uh->check = 0; 398 399 399 400 *skb_mac_header(skb) = IPPROTO_UDP; 400 - 401 - if (encap_type == UDP_ENCAP_ESPINUDP_NON_IKE) { 402 - udpdata32 = (__be32 *)(uh + 1); 403 - udpdata32[0] = udpdata32[1] = 0; 404 - return (struct ip_esp_hdr *)(udpdata32 + 2); 405 - } 406 401 407 402 return (struct ip_esp_hdr *)(uh + 1); 408 403 } ··· 453 460 switch (encap_type) { 454 461 default: 455 462 case UDP_ENCAP_ESPINUDP: 456 - case UDP_ENCAP_ESPINUDP_NON_IKE: 457 463 esph = esp6_output_udp_encap(skb, encap_type, esp, sport, dport); 458 464 break; 459 465 case TCP_ENCAP_ESPINTCP: ··· 815 823 source = th->source; 816 824 break; 817 825 case UDP_ENCAP_ESPINUDP: 818 - case UDP_ENCAP_ESPINUDP_NON_IKE: 819 826 source = uh->source; 820 827 break; 821 828 default: ··· 1223 1232 goto error; 1224 1233 case UDP_ENCAP_ESPINUDP: 1225 1234 x->props.header_len += sizeof(struct udphdr); 1226 - break; 1227 - case UDP_ENCAP_ESPINUDP_NON_IKE: 1228 - x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32); 1229 1235 break; 1230 1236 #ifdef CONFIG_INET6_ESPINTCP 1231 1237 case TCP_ENCAP_ESPINTCP:
+7 -13
net/ipv6/xfrm6_input.c
··· 109 109 /* Must be an IKE packet.. pass it through */ 110 110 return 1; 111 111 break; 112 - case UDP_ENCAP_ESPINUDP_NON_IKE: 113 - /* Check if this is a keepalive packet. If so, eat it. */ 114 - if (len == 1 && udpdata[0] == 0xff) { 115 - return -EINVAL; 116 - } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) && 117 - udpdata32[0] == 0 && udpdata32[1] == 0) { 118 - 119 - /* ESP Packet with Non-IKE marker */ 120 - len = sizeof(struct udphdr) + 2 * sizeof(u32); 121 - } else 122 - /* Must be an IKE packet.. pass it through */ 123 - return 1; 124 - break; 125 112 } 126 113 127 114 /* At this point we are sure that this is an ESPinUDP packet, ··· 265 278 x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6); 266 279 if (!x) 267 280 continue; 281 + 282 + if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) { 283 + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR); 284 + xfrm_state_put(x); 285 + x = NULL; 286 + continue; 287 + } 268 288 269 289 spin_lock(&x->lock); 270 290
+5 -2
net/xfrm/xfrm_compat.c
··· 98 98 }; 99 99 100 100 static const struct nla_policy compat_policy[XFRMA_MAX+1] = { 101 + [XFRMA_UNSPEC] = { .strict_start_type = XFRMA_SA_DIR }, 101 102 [XFRMA_SA] = { .len = XMSGSIZE(compat_xfrm_usersa_info)}, 102 103 [XFRMA_POLICY] = { .len = XMSGSIZE(compat_xfrm_userpolicy_info)}, 103 104 [XFRMA_LASTUSED] = { .type = NLA_U64}, ··· 130 129 [XFRMA_SET_MARK_MASK] = { .type = NLA_U32 }, 131 130 [XFRMA_IF_ID] = { .type = NLA_U32 }, 132 131 [XFRMA_MTIMER_THRESH] = { .type = NLA_U32 }, 132 + [XFRMA_SA_DIR] = NLA_POLICY_RANGE(NLA_U8, XFRM_SA_DIR_IN, XFRM_SA_DIR_OUT), 133 133 }; 134 134 135 135 static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb, ··· 279 277 case XFRMA_SET_MARK_MASK: 280 278 case XFRMA_IF_ID: 281 279 case XFRMA_MTIMER_THRESH: 280 + case XFRMA_SA_DIR: 282 281 return xfrm_nla_cpy(dst, src, nla_len(src)); 283 282 default: 284 - BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH); 283 + BUILD_BUG_ON(XFRMA_MAX != XFRMA_SA_DIR); 285 284 pr_warn_once("unsupported nla_type %d\n", src->nla_type); 286 285 return -EOPNOTSUPP; 287 286 } ··· 437 434 int err; 438 435 439 436 if (type > XFRMA_MAX) { 440 - BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH); 437 + BUILD_BUG_ON(XFRMA_MAX != XFRMA_SA_DIR); 441 438 NL_SET_ERR_MSG(extack, "Bad attribute"); 442 439 return -EOPNOTSUPP; 443 440 }
+6
net/xfrm/xfrm_device.c
··· 253 253 return -EINVAL; 254 254 } 255 255 256 + if ((xuo->flags & XFRM_OFFLOAD_INBOUND && x->dir == XFRM_SA_DIR_OUT) || 257 + (!(xuo->flags & XFRM_OFFLOAD_INBOUND) && x->dir == XFRM_SA_DIR_IN)) { 258 + NL_SET_ERR_MSG(extack, "Mismatched SA and offload direction"); 259 + return -EINVAL; 260 + } 261 + 256 262 is_packet_offload = xuo->flags & XFRM_OFFLOAD_PACKET; 257 263 258 264 /* We don't yet support UDP encapsulation and TFC padding. */
+11
net/xfrm/xfrm_input.c
··· 466 466 if (encap_type < 0 || (xo && xo->flags & XFRM_GRO)) { 467 467 x = xfrm_input_state(skb); 468 468 469 + if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) { 470 + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR); 471 + goto drop; 472 + } 473 + 469 474 if (unlikely(x->km.state != XFRM_STATE_VALID)) { 470 475 if (x->km.state == XFRM_STATE_ACQ) 471 476 XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR); ··· 573 568 secpath_reset(skb); 574 569 XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); 575 570 xfrm_audit_state_notfound(skb, family, spi, seq); 571 + goto drop; 572 + } 573 + 574 + if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) { 575 + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR); 576 + xfrm_state_put(x); 576 577 goto drop; 577 578 } 578 579
+6
net/xfrm/xfrm_policy.c
··· 2489 2489 2490 2490 x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, 2491 2491 family, policy->if_id); 2492 + if (x && x->dir && x->dir != XFRM_SA_DIR_OUT) { 2493 + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEDIRERROR); 2494 + xfrm_state_put(x); 2495 + error = -EINVAL; 2496 + goto fail; 2497 + } 2492 2498 2493 2499 if (x && x->km.state == XFRM_STATE_VALID) { 2494 2500 xfrm[nx++] = x;
+2
net/xfrm/xfrm_proc.c
··· 41 41 SNMP_MIB_ITEM("XfrmFwdHdrError", LINUX_MIB_XFRMFWDHDRERROR), 42 42 SNMP_MIB_ITEM("XfrmOutStateInvalid", LINUX_MIB_XFRMOUTSTATEINVALID), 43 43 SNMP_MIB_ITEM("XfrmAcquireError", LINUX_MIB_XFRMACQUIREERROR), 44 + SNMP_MIB_ITEM("XfrmOutStateDirError", LINUX_MIB_XFRMOUTSTATEDIRERROR), 45 + SNMP_MIB_ITEM("XfrmInStateDirError", LINUX_MIB_XFRMINSTATEDIRERROR), 44 46 SNMP_MIB_SENTINEL 45 47 }; 46 48
+2 -1
net/xfrm/xfrm_replay.c
··· 778 778 } 779 779 780 780 if (x->props.flags & XFRM_STATE_ESN) { 781 - if (replay_esn->replay_window == 0) { 781 + if (replay_esn->replay_window == 0 && 782 + (!x->dir || x->dir == XFRM_SA_DIR_IN)) { 782 783 NL_SET_ERR_MSG(extack, "ESN replay window must be > 0"); 783 784 return -EINVAL; 784 785 }
+8
net/xfrm/xfrm_state.c
··· 1292 1292 if (km_query(x, tmpl, pol) == 0) { 1293 1293 spin_lock_bh(&net->xfrm.xfrm_state_lock); 1294 1294 x->km.state = XFRM_STATE_ACQ; 1295 + x->dir = XFRM_SA_DIR_OUT; 1295 1296 list_add(&x->km.all, &net->xfrm.state_all); 1296 1297 XFRM_STATE_INSERT(bydst, &x->bydst, 1297 1298 net->xfrm.state_bydst + h, ··· 1745 1744 x->lastused = orig->lastused; 1746 1745 x->new_mapping = 0; 1747 1746 x->new_mapping_sport = 0; 1747 + x->dir = orig->dir; 1748 1748 1749 1749 return x; 1750 1750 ··· 1866 1864 } 1867 1865 1868 1866 if (x1->km.state == XFRM_STATE_ACQ) { 1867 + if (x->dir && x1->dir != x->dir) 1868 + goto out; 1869 + 1869 1870 __xfrm_state_insert(x); 1870 1871 x = NULL; 1872 + } else { 1873 + if (x1->dir != x->dir) 1874 + goto out; 1871 1875 } 1872 1876 err = 0; 1873 1877
+156 -6
net/xfrm/xfrm_user.c
··· 130 130 } 131 131 132 132 static inline int verify_replay(struct xfrm_usersa_info *p, 133 - struct nlattr **attrs, 133 + struct nlattr **attrs, u8 sa_dir, 134 134 struct netlink_ext_ack *extack) 135 135 { 136 136 struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL]; ··· 168 168 return -EINVAL; 169 169 } 170 170 171 + if (sa_dir == XFRM_SA_DIR_OUT) { 172 + if (rs->replay_window) { 173 + NL_SET_ERR_MSG(extack, "Replay window should be 0 for output SA"); 174 + return -EINVAL; 175 + } 176 + if (rs->seq || rs->seq_hi) { 177 + NL_SET_ERR_MSG(extack, 178 + "Replay seq and seq_hi should be 0 for output SA"); 179 + return -EINVAL; 180 + } 181 + if (rs->bmp_len) { 182 + NL_SET_ERR_MSG(extack, "Replay bmp_len should 0 for output SA"); 183 + return -EINVAL; 184 + } 185 + } 186 + 187 + if (sa_dir == XFRM_SA_DIR_IN) { 188 + if (rs->oseq || rs->oseq_hi) { 189 + NL_SET_ERR_MSG(extack, 190 + "Replay oseq and oseq_hi should be 0 for input SA"); 191 + return -EINVAL; 192 + } 193 + } 194 + 171 195 return 0; 172 196 } 173 197 ··· 200 176 struct netlink_ext_ack *extack) 201 177 { 202 178 int err; 179 + u8 sa_dir = attrs[XFRMA_SA_DIR] ? nla_get_u8(attrs[XFRMA_SA_DIR]) : 0; 203 180 204 181 err = -EINVAL; 205 182 switch (p->family) { ··· 359 334 goto out; 360 335 if ((err = verify_sec_ctx_len(attrs, extack))) 361 336 goto out; 362 - if ((err = verify_replay(p, attrs, extack))) 337 + if ((err = verify_replay(p, attrs, sa_dir, extack))) 363 338 goto out; 364 339 365 340 err = -EINVAL; ··· 382 357 NL_SET_ERR_MSG(extack, "MTIMER_THRESH attribute can only be set on ENCAP states"); 383 358 err = -EINVAL; 384 359 goto out; 360 + } 361 + 362 + if (sa_dir == XFRM_SA_DIR_OUT) { 363 + NL_SET_ERR_MSG(extack, 364 + "MTIMER_THRESH attribute should not be set on output SA"); 365 + err = -EINVAL; 366 + goto out; 367 + } 368 + } 369 + 370 + if (sa_dir == XFRM_SA_DIR_OUT) { 371 + if (p->flags & XFRM_STATE_DECAP_DSCP) { 372 + NL_SET_ERR_MSG(extack, "Flag DECAP_DSCP should not be set for output SA"); 373 + err = -EINVAL; 374 + goto out; 375 + } 376 + 377 + if (p->flags & XFRM_STATE_ICMP) { 378 + NL_SET_ERR_MSG(extack, "Flag ICMP should not be set for output SA"); 379 + err = -EINVAL; 380 + goto out; 381 + } 382 + 383 + if (p->flags & XFRM_STATE_WILDRECV) { 384 + NL_SET_ERR_MSG(extack, "Flag WILDRECV should not be set for output SA"); 385 + err = -EINVAL; 386 + goto out; 387 + } 388 + 389 + if (p->replay_window) { 390 + NL_SET_ERR_MSG(extack, "Replay window should be 0 for output SA"); 391 + err = -EINVAL; 392 + goto out; 393 + } 394 + 395 + if (attrs[XFRMA_REPLAY_VAL]) { 396 + struct xfrm_replay_state *replay; 397 + 398 + replay = nla_data(attrs[XFRMA_REPLAY_VAL]); 399 + 400 + if (replay->seq || replay->bitmap) { 401 + NL_SET_ERR_MSG(extack, 402 + "Replay seq and bitmap should be 0 for output SA"); 403 + err = -EINVAL; 404 + goto out; 405 + } 406 + } 407 + } 408 + 409 + if (sa_dir == XFRM_SA_DIR_IN) { 410 + if (p->flags & XFRM_STATE_NOPMTUDISC) { 411 + NL_SET_ERR_MSG(extack, "Flag NOPMTUDISC should not be set for input SA"); 412 + err = -EINVAL; 413 + goto out; 414 + } 415 + 416 + if (attrs[XFRMA_SA_EXTRA_FLAGS]) { 417 + u32 xflags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]); 418 + 419 + if (xflags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) { 420 + NL_SET_ERR_MSG(extack, "Flag DONT_ENCAP_DSCP should not be set for input SA"); 421 + err = -EINVAL; 422 + goto out; 423 + } 424 + 425 + if (xflags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP) { 426 + NL_SET_ERR_MSG(extack, "Flag OSEQ_MAY_WRAP should not be set for input SA"); 427 + err = -EINVAL; 428 + goto out; 429 + } 430 + 385 431 } 386 432 } 387 433 ··· 829 733 830 734 if (attrs[XFRMA_IF_ID]) 831 735 x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]); 736 + 737 + if (attrs[XFRMA_SA_DIR]) 738 + x->dir = nla_get_u8(attrs[XFRMA_SA_DIR]); 832 739 833 740 err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV], extack); 834 741 if (err) ··· 1281 1182 if (ret) 1282 1183 goto out; 1283 1184 } 1284 - if (x->mapping_maxage) 1185 + if (x->mapping_maxage) { 1285 1186 ret = nla_put_u32(skb, XFRMA_MTIMER_THRESH, x->mapping_maxage); 1187 + if (ret) 1188 + goto out; 1189 + } 1190 + if (x->dir) 1191 + ret = nla_put_u8(skb, XFRMA_SA_DIR, x->dir); 1286 1192 out: 1287 1193 return ret; 1288 1194 } ··· 1721 1617 err = xfrm_alloc_spi(x, p->min, p->max, extack); 1722 1618 if (err) 1723 1619 goto out; 1620 + 1621 + if (attrs[XFRMA_SA_DIR]) 1622 + x->dir = nla_get_u8(attrs[XFRMA_SA_DIR]); 1724 1623 1725 1624 resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); 1726 1625 if (IS_ERR(resp_skb)) { ··· 2509 2402 + nla_total_size_64bit(sizeof(struct xfrm_lifetime_cur)) 2510 2403 + nla_total_size(sizeof(struct xfrm_mark)) 2511 2404 + nla_total_size(4) /* XFRM_AE_RTHR */ 2512 - + nla_total_size(4); /* XFRM_AE_ETHR */ 2405 + + nla_total_size(4) /* XFRM_AE_ETHR */ 2406 + + nla_total_size(sizeof(x->dir)); /* XFRMA_SA_DIR */ 2513 2407 } 2514 2408 2515 2409 static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c) ··· 2566 2458 err = xfrm_if_id_put(skb, x->if_id); 2567 2459 if (err) 2568 2460 goto out_cancel; 2461 + 2462 + if (x->dir) { 2463 + err = nla_put_u8(skb, XFRMA_SA_DIR, x->dir); 2464 + if (err) 2465 + goto out_cancel; 2466 + } 2569 2467 2570 2468 nlmsg_end(skb, nlh); 2571 2469 return 0; ··· 3132 3018 #undef XMSGSIZE 3133 3019 3134 3020 const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { 3021 + [XFRMA_UNSPEC] = { .strict_start_type = XFRMA_SA_DIR }, 3135 3022 [XFRMA_SA] = { .len = sizeof(struct xfrm_usersa_info)}, 3136 3023 [XFRMA_POLICY] = { .len = sizeof(struct xfrm_userpolicy_info)}, 3137 3024 [XFRMA_LASTUSED] = { .type = NLA_U64}, ··· 3164 3049 [XFRMA_SET_MARK_MASK] = { .type = NLA_U32 }, 3165 3050 [XFRMA_IF_ID] = { .type = NLA_U32 }, 3166 3051 [XFRMA_MTIMER_THRESH] = { .type = NLA_U32 }, 3052 + [XFRMA_SA_DIR] = NLA_POLICY_RANGE(NLA_U8, XFRM_SA_DIR_IN, XFRM_SA_DIR_OUT), 3167 3053 }; 3168 3054 EXPORT_SYMBOL_GPL(xfrma_policy); 3169 3055 ··· 3212 3096 [XFRM_MSG_SETDEFAULT - XFRM_MSG_BASE] = { .doit = xfrm_set_default }, 3213 3097 [XFRM_MSG_GETDEFAULT - XFRM_MSG_BASE] = { .doit = xfrm_get_default }, 3214 3098 }; 3099 + 3100 + static int xfrm_reject_unused_attr(int type, struct nlattr **attrs, 3101 + struct netlink_ext_ack *extack) 3102 + { 3103 + if (attrs[XFRMA_SA_DIR]) { 3104 + switch (type) { 3105 + case XFRM_MSG_NEWSA: 3106 + case XFRM_MSG_UPDSA: 3107 + case XFRM_MSG_ALLOCSPI: 3108 + break; 3109 + default: 3110 + NL_SET_ERR_MSG(extack, "Invalid attribute SA_DIR"); 3111 + return -EINVAL; 3112 + } 3113 + } 3114 + 3115 + return 0; 3116 + } 3215 3117 3216 3118 static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, 3217 3119 struct netlink_ext_ack *extack) ··· 3290 3156 if (err < 0) 3291 3157 goto err; 3292 3158 3159 + if (!link->nla_pol || link->nla_pol == xfrma_policy) { 3160 + err = xfrm_reject_unused_attr((type + XFRM_MSG_BASE), attrs, extack); 3161 + if (err < 0) 3162 + goto err; 3163 + } 3164 + 3293 3165 if (link->doit == NULL) { 3294 3166 err = -EINVAL; 3295 3167 goto err; ··· 3329 3189 3330 3190 static inline unsigned int xfrm_expire_msgsize(void) 3331 3191 { 3332 - return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)) 3333 - + nla_total_size(sizeof(struct xfrm_mark)); 3192 + return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)) + 3193 + nla_total_size(sizeof(struct xfrm_mark)) + 3194 + nla_total_size(sizeof_field(struct xfrm_state, dir)); 3334 3195 } 3335 3196 3336 3197 static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c) ··· 3357 3216 err = xfrm_if_id_put(skb, x->if_id); 3358 3217 if (err) 3359 3218 return err; 3219 + 3220 + if (x->dir) { 3221 + err = nla_put_u8(skb, XFRMA_SA_DIR, x->dir); 3222 + if (err) 3223 + return err; 3224 + } 3360 3225 3361 3226 nlmsg_end(skb, nlh); 3362 3227 return 0; ··· 3470 3323 3471 3324 if (x->mapping_maxage) 3472 3325 l += nla_total_size(sizeof(x->mapping_maxage)); 3326 + 3327 + if (x->dir) 3328 + l += nla_total_size(sizeof(x->dir)); 3473 3329 3474 3330 return l; 3475 3331 }