mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-27 12:57:53 +00:00
ipsec-next-2024-05-03
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH7ZpcWbFyOOp6OJbrB3Eaf9PW7cFAmY0mEIACgkQrB3Eaf9P W7fU7g//bQyydwei/4Vo+cNCPp82k8wL/qhDY3IjN10PfJOSNmeCAcSgkuuHTRSx g/hoxZEVzLrQT5bt+Sb38JxADFiL787GjdGEUy1gzF7CnDKcGT5KnydYNjDqDVGt nOv9kAGfWIkMKdNqrhHifddPMWd+ZqvpUcFz5olvqIE2mpNgMwy2i3NID9bNAV31 v5AEvNINa1LKOhX9cEka8iPQXwp+I6yTLqyOd4VciOuFr8dPg0FQqFaYR+OtMsV0 kIxdGTVfmRWaNgq/Tsg4z/2rXEwmEjTWzAhNVGu8o8L3JozXOvbjIrDG7Ws6qB3V XTFl8ueRMk0UCTlY/QAfip5H7IlAo+H0FUBC45FNP1UhHeWisXT4D5rqAEqQTlZR bddtuueLZyKclFpXRNi+/8vdDrXhhEzeNINkc52Ef33rUTtZJR8bXrEUKzaYCIuF ldub0PA3+e5wvwIxq5/Chc/+MIaIHnXBMUmbCJSPnMrupBQtO+i6arPQcbtaBAgS YyVGTRk9YN0UAjSriIuiViLlgUCMsvsWgfSz9rd0PE54MFBrvcLPeCtPxKZ+sTVG Y2iSZ8d3ThvsMiQVNU8gj3SlTY1oTvuaijDDGjnR0nWkxV9LMJHCPKfIzsbOKLJe +ee5hKP4TOFygnV58BkqdGK/LavNpouTIbrM43hgmJ0IX9kSt4o= =QiGZ -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
179a6f5df8
18 changed files with 219 additions and 62 deletions
|
@ -73,6 +73,9 @@ XfrmAcquireError:
|
|||
XfrmFwdHdrError:
|
||||
Forward routing of a packet is not allowed
|
||||
|
||||
XfrmInStateDirError:
|
||||
State direction mismatch (lookup found an output state on the input path, expected input or no direction)
|
||||
|
||||
Outbound errors
|
||||
~~~~~~~~~~~~~~~
|
||||
XfrmOutError:
|
||||
|
@ -111,3 +114,6 @@ XfrmOutPolError:
|
|||
|
||||
XfrmOutStateInvalid:
|
||||
State is invalid, perhaps expired
|
||||
|
||||
XfrmOutStateDirError:
|
||||
State direction mismatch (lookup found an input state on the output path, expected output or no direction)
|
||||
|
|
|
@ -291,6 +291,7 @@ struct xfrm_state {
|
|||
/* Private data of this transformer, format is opaque,
|
||||
* interpreted by xfrm_type methods. */
|
||||
void *data;
|
||||
u8 dir;
|
||||
};
|
||||
|
||||
static inline struct net *xs_net(struct xfrm_state *x)
|
||||
|
|
|
@ -337,6 +337,8 @@ enum
|
|||
LINUX_MIB_XFRMFWDHDRERROR, /* XfrmFwdHdrError*/
|
||||
LINUX_MIB_XFRMOUTSTATEINVALID, /* XfrmOutStateInvalid */
|
||||
LINUX_MIB_XFRMACQUIREERROR, /* XfrmAcquireError */
|
||||
LINUX_MIB_XFRMOUTSTATEDIRERROR, /* XfrmOutStateDirError */
|
||||
LINUX_MIB_XFRMINSTATEDIRERROR, /* XfrmInStateDirError */
|
||||
__LINUX_MIB_XFRMMAX
|
||||
};
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ struct udphdr {
|
|||
#define UDP_GRO 104 /* This socket can receive UDP GRO packets */
|
||||
|
||||
/* UDP encapsulation types */
|
||||
#define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
|
||||
#define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* unused draft-ietf-ipsec-nat-t-ike-00/01 */
|
||||
#define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-06 */
|
||||
#define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */
|
||||
#define UDP_ENCAP_GTP0 4 /* GSM TS 09.60 */
|
||||
|
|
|
@ -141,6 +141,11 @@ enum {
|
|||
XFRM_POLICY_MAX = 3
|
||||
};
|
||||
|
||||
enum xfrm_sa_dir {
|
||||
XFRM_SA_DIR_IN = 1,
|
||||
XFRM_SA_DIR_OUT = 2
|
||||
};
|
||||
|
||||
enum {
|
||||
XFRM_SHARE_ANY, /* No limitations */
|
||||
XFRM_SHARE_SESSION, /* For this session only */
|
||||
|
@ -315,6 +320,7 @@ enum xfrm_attr_type_t {
|
|||
XFRMA_SET_MARK_MASK, /* __u32 */
|
||||
XFRMA_IF_ID, /* __u32 */
|
||||
XFRMA_MTIMER_THRESH, /* __u32 in seconds for input SA */
|
||||
XFRMA_SA_DIR, /* __u8 */
|
||||
__XFRMA_MAX
|
||||
|
||||
#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */
|
||||
|
|
|
@ -348,7 +348,6 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
|
|||
__be16 dport)
|
||||
{
|
||||
struct udphdr *uh;
|
||||
__be32 *udpdata32;
|
||||
unsigned int len;
|
||||
|
||||
len = skb->len + esp->tailen - skb_transport_offset(skb);
|
||||
|
@ -363,12 +362,6 @@ static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
|
|||
|
||||
*skb_mac_header(skb) = IPPROTO_UDP;
|
||||
|
||||
if (encap_type == UDP_ENCAP_ESPINUDP_NON_IKE) {
|
||||
udpdata32 = (__be32 *)(uh + 1);
|
||||
udpdata32[0] = udpdata32[1] = 0;
|
||||
return (struct ip_esp_hdr *)(udpdata32 + 2);
|
||||
}
|
||||
|
||||
return (struct ip_esp_hdr *)(uh + 1);
|
||||
}
|
||||
|
||||
|
@ -424,7 +417,6 @@ static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb,
|
|||
switch (encap_type) {
|
||||
default:
|
||||
case UDP_ENCAP_ESPINUDP:
|
||||
case UDP_ENCAP_ESPINUDP_NON_IKE:
|
||||
esph = esp_output_udp_encap(skb, encap_type, esp, sport, dport);
|
||||
break;
|
||||
case TCP_ENCAP_ESPINTCP:
|
||||
|
@ -776,7 +768,6 @@ int esp_input_done2(struct sk_buff *skb, int err)
|
|||
source = th->source;
|
||||
break;
|
||||
case UDP_ENCAP_ESPINUDP:
|
||||
case UDP_ENCAP_ESPINUDP_NON_IKE:
|
||||
source = uh->source;
|
||||
break;
|
||||
default:
|
||||
|
@ -1180,9 +1171,6 @@ static int esp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
|
|||
case UDP_ENCAP_ESPINUDP:
|
||||
x->props.header_len += sizeof(struct udphdr);
|
||||
break;
|
||||
case UDP_ENCAP_ESPINUDP_NON_IKE:
|
||||
x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32);
|
||||
break;
|
||||
#ifdef CONFIG_INET_ESPINTCP
|
||||
case TCP_ENCAP_ESPINTCP:
|
||||
/* only the length field, TCP encap is done by
|
||||
|
|
|
@ -2712,8 +2712,6 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
|
|||
#ifdef CONFIG_XFRM
|
||||
case UDP_ENCAP_ESPINUDP:
|
||||
set_xfrm_gro_udp_encap_rcv(val, sk->sk_family, sk);
|
||||
fallthrough;
|
||||
case UDP_ENCAP_ESPINUDP_NON_IKE:
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (sk->sk_family == AF_INET6)
|
||||
WRITE_ONCE(up->encap_rcv,
|
||||
|
|
|
@ -113,19 +113,6 @@ static int __xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb, bool pull
|
|||
/* Must be an IKE packet.. pass it through */
|
||||
return 1;
|
||||
break;
|
||||
case UDP_ENCAP_ESPINUDP_NON_IKE:
|
||||
/* Check if this is a keepalive packet. If so, eat it. */
|
||||
if (len == 1 && udpdata[0] == 0xff) {
|
||||
return -EINVAL;
|
||||
} else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
|
||||
udpdata32[0] == 0 && udpdata32[1] == 0) {
|
||||
|
||||
/* ESP Packet with Non-IKE marker */
|
||||
len = sizeof(struct udphdr) + 2 * sizeof(u32);
|
||||
} else
|
||||
/* Must be an IKE packet.. pass it through */
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* At this point we are sure that this is an ESPinUDP packet,
|
||||
|
|
|
@ -384,7 +384,6 @@ static struct ip_esp_hdr *esp6_output_udp_encap(struct sk_buff *skb,
|
|||
__be16 dport)
|
||||
{
|
||||
struct udphdr *uh;
|
||||
__be32 *udpdata32;
|
||||
unsigned int len;
|
||||
|
||||
len = skb->len + esp->tailen - skb_transport_offset(skb);
|
||||
|
@ -399,12 +398,6 @@ static struct ip_esp_hdr *esp6_output_udp_encap(struct sk_buff *skb,
|
|||
|
||||
*skb_mac_header(skb) = IPPROTO_UDP;
|
||||
|
||||
if (encap_type == UDP_ENCAP_ESPINUDP_NON_IKE) {
|
||||
udpdata32 = (__be32 *)(uh + 1);
|
||||
udpdata32[0] = udpdata32[1] = 0;
|
||||
return (struct ip_esp_hdr *)(udpdata32 + 2);
|
||||
}
|
||||
|
||||
return (struct ip_esp_hdr *)(uh + 1);
|
||||
}
|
||||
|
||||
|
@ -460,7 +453,6 @@ static int esp6_output_encap(struct xfrm_state *x, struct sk_buff *skb,
|
|||
switch (encap_type) {
|
||||
default:
|
||||
case UDP_ENCAP_ESPINUDP:
|
||||
case UDP_ENCAP_ESPINUDP_NON_IKE:
|
||||
esph = esp6_output_udp_encap(skb, encap_type, esp, sport, dport);
|
||||
break;
|
||||
case TCP_ENCAP_ESPINTCP:
|
||||
|
@ -823,7 +815,6 @@ int esp6_input_done2(struct sk_buff *skb, int err)
|
|||
source = th->source;
|
||||
break;
|
||||
case UDP_ENCAP_ESPINUDP:
|
||||
case UDP_ENCAP_ESPINUDP_NON_IKE:
|
||||
source = uh->source;
|
||||
break;
|
||||
default:
|
||||
|
@ -1233,9 +1224,6 @@ static int esp6_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
|
|||
case UDP_ENCAP_ESPINUDP:
|
||||
x->props.header_len += sizeof(struct udphdr);
|
||||
break;
|
||||
case UDP_ENCAP_ESPINUDP_NON_IKE:
|
||||
x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32);
|
||||
break;
|
||||
#ifdef CONFIG_INET6_ESPINTCP
|
||||
case TCP_ENCAP_ESPINTCP:
|
||||
/* only the length field, TCP encap is done by
|
||||
|
|
|
@ -109,19 +109,6 @@ static int __xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb, bool pull
|
|||
/* Must be an IKE packet.. pass it through */
|
||||
return 1;
|
||||
break;
|
||||
case UDP_ENCAP_ESPINUDP_NON_IKE:
|
||||
/* Check if this is a keepalive packet. If so, eat it. */
|
||||
if (len == 1 && udpdata[0] == 0xff) {
|
||||
return -EINVAL;
|
||||
} else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
|
||||
udpdata32[0] == 0 && udpdata32[1] == 0) {
|
||||
|
||||
/* ESP Packet with Non-IKE marker */
|
||||
len = sizeof(struct udphdr) + 2 * sizeof(u32);
|
||||
} else
|
||||
/* Must be an IKE packet.. pass it through */
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* At this point we are sure that this is an ESPinUDP packet,
|
||||
|
@ -279,6 +266,13 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
|
|||
if (!x)
|
||||
continue;
|
||||
|
||||
if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
|
||||
xfrm_state_put(x);
|
||||
x = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_lock(&x->lock);
|
||||
|
||||
if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) &&
|
||||
|
|
|
@ -98,6 +98,7 @@ static const int compat_msg_min[XFRM_NR_MSGTYPES] = {
|
|||
};
|
||||
|
||||
static const struct nla_policy compat_policy[XFRMA_MAX+1] = {
|
||||
[XFRMA_UNSPEC] = { .strict_start_type = XFRMA_SA_DIR },
|
||||
[XFRMA_SA] = { .len = XMSGSIZE(compat_xfrm_usersa_info)},
|
||||
[XFRMA_POLICY] = { .len = XMSGSIZE(compat_xfrm_userpolicy_info)},
|
||||
[XFRMA_LASTUSED] = { .type = NLA_U64},
|
||||
|
@ -129,6 +130,7 @@ static const struct nla_policy compat_policy[XFRMA_MAX+1] = {
|
|||
[XFRMA_SET_MARK_MASK] = { .type = NLA_U32 },
|
||||
[XFRMA_IF_ID] = { .type = NLA_U32 },
|
||||
[XFRMA_MTIMER_THRESH] = { .type = NLA_U32 },
|
||||
[XFRMA_SA_DIR] = NLA_POLICY_RANGE(NLA_U8, XFRM_SA_DIR_IN, XFRM_SA_DIR_OUT),
|
||||
};
|
||||
|
||||
static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb,
|
||||
|
@ -277,9 +279,10 @@ static int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src)
|
|||
case XFRMA_SET_MARK_MASK:
|
||||
case XFRMA_IF_ID:
|
||||
case XFRMA_MTIMER_THRESH:
|
||||
case XFRMA_SA_DIR:
|
||||
return xfrm_nla_cpy(dst, src, nla_len(src));
|
||||
default:
|
||||
BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
|
||||
BUILD_BUG_ON(XFRMA_MAX != XFRMA_SA_DIR);
|
||||
pr_warn_once("unsupported nla_type %d\n", src->nla_type);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -434,7 +437,7 @@ static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla,
|
|||
int err;
|
||||
|
||||
if (type > XFRMA_MAX) {
|
||||
BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
|
||||
BUILD_BUG_ON(XFRMA_MAX != XFRMA_SA_DIR);
|
||||
NL_SET_ERR_MSG(extack, "Bad attribute");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
|
@ -253,6 +253,12 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((xuo->flags & XFRM_OFFLOAD_INBOUND && x->dir == XFRM_SA_DIR_OUT) ||
|
||||
(!(xuo->flags & XFRM_OFFLOAD_INBOUND) && x->dir == XFRM_SA_DIR_IN)) {
|
||||
NL_SET_ERR_MSG(extack, "Mismatched SA and offload direction");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
is_packet_offload = xuo->flags & XFRM_OFFLOAD_PACKET;
|
||||
|
||||
/* We don't yet support UDP encapsulation and TFC padding. */
|
||||
|
|
|
@ -466,6 +466,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
|
|||
if (encap_type < 0 || (xo && xo->flags & XFRM_GRO)) {
|
||||
x = xfrm_input_state(skb);
|
||||
|
||||
if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (unlikely(x->km.state != XFRM_STATE_VALID)) {
|
||||
if (x->km.state == XFRM_STATE_ACQ)
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
|
||||
|
@ -571,6 +576,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
|
|||
goto drop;
|
||||
}
|
||||
|
||||
if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
|
||||
xfrm_state_put(x);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
skb->mark = xfrm_smark_get(skb->mark, x);
|
||||
|
||||
sp->xvec[sp->len++] = x;
|
||||
|
|
|
@ -2489,6 +2489,12 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
|
|||
|
||||
x = xfrm_state_find(remote, local, fl, tmpl, policy, &error,
|
||||
family, policy->if_id);
|
||||
if (x && x->dir && x->dir != XFRM_SA_DIR_OUT) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEDIRERROR);
|
||||
xfrm_state_put(x);
|
||||
error = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (x && x->km.state == XFRM_STATE_VALID) {
|
||||
xfrm[nx++] = x;
|
||||
|
|
|
@ -41,6 +41,8 @@ static const struct snmp_mib xfrm_mib_list[] = {
|
|||
SNMP_MIB_ITEM("XfrmFwdHdrError", LINUX_MIB_XFRMFWDHDRERROR),
|
||||
SNMP_MIB_ITEM("XfrmOutStateInvalid", LINUX_MIB_XFRMOUTSTATEINVALID),
|
||||
SNMP_MIB_ITEM("XfrmAcquireError", LINUX_MIB_XFRMACQUIREERROR),
|
||||
SNMP_MIB_ITEM("XfrmOutStateDirError", LINUX_MIB_XFRMOUTSTATEDIRERROR),
|
||||
SNMP_MIB_ITEM("XfrmInStateDirError", LINUX_MIB_XFRMINSTATEDIRERROR),
|
||||
SNMP_MIB_SENTINEL
|
||||
};
|
||||
|
||||
|
|
|
@ -778,7 +778,8 @@ int xfrm_init_replay(struct xfrm_state *x, struct netlink_ext_ack *extack)
|
|||
}
|
||||
|
||||
if (x->props.flags & XFRM_STATE_ESN) {
|
||||
if (replay_esn->replay_window == 0) {
|
||||
if (replay_esn->replay_window == 0 &&
|
||||
(!x->dir || x->dir == XFRM_SA_DIR_IN)) {
|
||||
NL_SET_ERR_MSG(extack, "ESN replay window must be > 0");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -1292,6 +1292,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
|
|||
if (km_query(x, tmpl, pol) == 0) {
|
||||
spin_lock_bh(&net->xfrm.xfrm_state_lock);
|
||||
x->km.state = XFRM_STATE_ACQ;
|
||||
x->dir = XFRM_SA_DIR_OUT;
|
||||
list_add(&x->km.all, &net->xfrm.state_all);
|
||||
XFRM_STATE_INSERT(bydst, &x->bydst,
|
||||
net->xfrm.state_bydst + h,
|
||||
|
@ -1744,6 +1745,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
|
|||
x->lastused = orig->lastused;
|
||||
x->new_mapping = 0;
|
||||
x->new_mapping_sport = 0;
|
||||
x->dir = orig->dir;
|
||||
|
||||
return x;
|
||||
|
||||
|
@ -1864,8 +1866,14 @@ int xfrm_state_update(struct xfrm_state *x)
|
|||
}
|
||||
|
||||
if (x1->km.state == XFRM_STATE_ACQ) {
|
||||
if (x->dir && x1->dir != x->dir)
|
||||
goto out;
|
||||
|
||||
__xfrm_state_insert(x);
|
||||
x = NULL;
|
||||
} else {
|
||||
if (x1->dir != x->dir)
|
||||
goto out;
|
||||
}
|
||||
err = 0;
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ static inline int verify_sec_ctx_len(struct nlattr **attrs, struct netlink_ext_a
|
|||
}
|
||||
|
||||
static inline int verify_replay(struct xfrm_usersa_info *p,
|
||||
struct nlattr **attrs,
|
||||
struct nlattr **attrs, u8 sa_dir,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
|
||||
|
@ -168,6 +168,30 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sa_dir == XFRM_SA_DIR_OUT) {
|
||||
if (rs->replay_window) {
|
||||
NL_SET_ERR_MSG(extack, "Replay window should be 0 for output SA");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (rs->seq || rs->seq_hi) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Replay seq and seq_hi should be 0 for output SA");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (rs->bmp_len) {
|
||||
NL_SET_ERR_MSG(extack, "Replay bmp_len should 0 for output SA");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (sa_dir == XFRM_SA_DIR_IN) {
|
||||
if (rs->oseq || rs->oseq_hi) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Replay oseq and oseq_hi should be 0 for input SA");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -176,6 +200,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int err;
|
||||
u8 sa_dir = attrs[XFRMA_SA_DIR] ? nla_get_u8(attrs[XFRMA_SA_DIR]) : 0;
|
||||
|
||||
err = -EINVAL;
|
||||
switch (p->family) {
|
||||
|
@ -334,7 +359,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
|
|||
goto out;
|
||||
if ((err = verify_sec_ctx_len(attrs, extack)))
|
||||
goto out;
|
||||
if ((err = verify_replay(p, attrs, extack)))
|
||||
if ((err = verify_replay(p, attrs, sa_dir, extack)))
|
||||
goto out;
|
||||
|
||||
err = -EINVAL;
|
||||
|
@ -358,6 +383,77 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
|
|||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sa_dir == XFRM_SA_DIR_OUT) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"MTIMER_THRESH attribute should not be set on output SA");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (sa_dir == XFRM_SA_DIR_OUT) {
|
||||
if (p->flags & XFRM_STATE_DECAP_DSCP) {
|
||||
NL_SET_ERR_MSG(extack, "Flag DECAP_DSCP should not be set for output SA");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (p->flags & XFRM_STATE_ICMP) {
|
||||
NL_SET_ERR_MSG(extack, "Flag ICMP should not be set for output SA");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (p->flags & XFRM_STATE_WILDRECV) {
|
||||
NL_SET_ERR_MSG(extack, "Flag WILDRECV should not be set for output SA");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (p->replay_window) {
|
||||
NL_SET_ERR_MSG(extack, "Replay window should be 0 for output SA");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (attrs[XFRMA_REPLAY_VAL]) {
|
||||
struct xfrm_replay_state *replay;
|
||||
|
||||
replay = nla_data(attrs[XFRMA_REPLAY_VAL]);
|
||||
|
||||
if (replay->seq || replay->bitmap) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Replay seq and bitmap should be 0 for output SA");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sa_dir == XFRM_SA_DIR_IN) {
|
||||
if (p->flags & XFRM_STATE_NOPMTUDISC) {
|
||||
NL_SET_ERR_MSG(extack, "Flag NOPMTUDISC should not be set for input SA");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (attrs[XFRMA_SA_EXTRA_FLAGS]) {
|
||||
u32 xflags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]);
|
||||
|
||||
if (xflags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) {
|
||||
NL_SET_ERR_MSG(extack, "Flag DONT_ENCAP_DSCP should not be set for input SA");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (xflags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP) {
|
||||
NL_SET_ERR_MSG(extack, "Flag OSEQ_MAY_WRAP should not be set for input SA");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -734,6 +830,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
|
|||
if (attrs[XFRMA_IF_ID])
|
||||
x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
||||
|
||||
if (attrs[XFRMA_SA_DIR])
|
||||
x->dir = nla_get_u8(attrs[XFRMA_SA_DIR]);
|
||||
|
||||
err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV], extack);
|
||||
if (err)
|
||||
goto error;
|
||||
|
@ -1182,8 +1281,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
|
|||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
if (x->mapping_maxage)
|
||||
if (x->mapping_maxage) {
|
||||
ret = nla_put_u32(skb, XFRMA_MTIMER_THRESH, x->mapping_maxage);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
if (x->dir)
|
||||
ret = nla_put_u8(skb, XFRMA_SA_DIR, x->dir);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@ -1618,6 +1722,9 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
if (err)
|
||||
goto out;
|
||||
|
||||
if (attrs[XFRMA_SA_DIR])
|
||||
x->dir = nla_get_u8(attrs[XFRMA_SA_DIR]);
|
||||
|
||||
resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
|
||||
if (IS_ERR(resp_skb)) {
|
||||
err = PTR_ERR(resp_skb);
|
||||
|
@ -2402,7 +2509,8 @@ static inline unsigned int xfrm_aevent_msgsize(struct xfrm_state *x)
|
|||
+ nla_total_size_64bit(sizeof(struct xfrm_lifetime_cur))
|
||||
+ nla_total_size(sizeof(struct xfrm_mark))
|
||||
+ nla_total_size(4) /* XFRM_AE_RTHR */
|
||||
+ nla_total_size(4); /* XFRM_AE_ETHR */
|
||||
+ nla_total_size(4) /* XFRM_AE_ETHR */
|
||||
+ nla_total_size(sizeof(x->dir)); /* XFRMA_SA_DIR */
|
||||
}
|
||||
|
||||
static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
|
||||
|
@ -2459,6 +2567,12 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct
|
|||
if (err)
|
||||
goto out_cancel;
|
||||
|
||||
if (x->dir) {
|
||||
err = nla_put_u8(skb, XFRMA_SA_DIR, x->dir);
|
||||
if (err)
|
||||
goto out_cancel;
|
||||
}
|
||||
|
||||
nlmsg_end(skb, nlh);
|
||||
return 0;
|
||||
|
||||
|
@ -3018,6 +3132,7 @@ EXPORT_SYMBOL_GPL(xfrm_msg_min);
|
|||
#undef XMSGSIZE
|
||||
|
||||
const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
|
||||
[XFRMA_UNSPEC] = { .strict_start_type = XFRMA_SA_DIR },
|
||||
[XFRMA_SA] = { .len = sizeof(struct xfrm_usersa_info)},
|
||||
[XFRMA_POLICY] = { .len = sizeof(struct xfrm_userpolicy_info)},
|
||||
[XFRMA_LASTUSED] = { .type = NLA_U64},
|
||||
|
@ -3049,6 +3164,7 @@ const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
|
|||
[XFRMA_SET_MARK_MASK] = { .type = NLA_U32 },
|
||||
[XFRMA_IF_ID] = { .type = NLA_U32 },
|
||||
[XFRMA_MTIMER_THRESH] = { .type = NLA_U32 },
|
||||
[XFRMA_SA_DIR] = NLA_POLICY_RANGE(NLA_U8, XFRM_SA_DIR_IN, XFRM_SA_DIR_OUT),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(xfrma_policy);
|
||||
|
||||
|
@ -3097,6 +3213,24 @@ static const struct xfrm_link {
|
|||
[XFRM_MSG_GETDEFAULT - XFRM_MSG_BASE] = { .doit = xfrm_get_default },
|
||||
};
|
||||
|
||||
static int xfrm_reject_unused_attr(int type, struct nlattr **attrs,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
if (attrs[XFRMA_SA_DIR]) {
|
||||
switch (type) {
|
||||
case XFRM_MSG_NEWSA:
|
||||
case XFRM_MSG_UPDSA:
|
||||
case XFRM_MSG_ALLOCSPI:
|
||||
break;
|
||||
default:
|
||||
NL_SET_ERR_MSG(extack, "Invalid attribute SA_DIR");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
|
@ -3156,6 +3290,12 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
if (err < 0)
|
||||
goto err;
|
||||
|
||||
if (!link->nla_pol || link->nla_pol == xfrma_policy) {
|
||||
err = xfrm_reject_unused_attr((type + XFRM_MSG_BASE), attrs, extack);
|
||||
if (err < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (link->doit == NULL) {
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
|
@ -3189,8 +3329,9 @@ static void xfrm_netlink_rcv(struct sk_buff *skb)
|
|||
|
||||
static inline unsigned int xfrm_expire_msgsize(void)
|
||||
{
|
||||
return NLMSG_ALIGN(sizeof(struct xfrm_user_expire))
|
||||
+ nla_total_size(sizeof(struct xfrm_mark));
|
||||
return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)) +
|
||||
nla_total_size(sizeof(struct xfrm_mark)) +
|
||||
nla_total_size(sizeof_field(struct xfrm_state, dir));
|
||||
}
|
||||
|
||||
static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
|
||||
|
@ -3217,6 +3358,12 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (x->dir) {
|
||||
err = nla_put_u8(skb, XFRMA_SA_DIR, x->dir);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
nlmsg_end(skb, nlh);
|
||||
return 0;
|
||||
}
|
||||
|
@ -3324,6 +3471,9 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x)
|
|||
if (x->mapping_maxage)
|
||||
l += nla_total_size(sizeof(x->mapping_maxage));
|
||||
|
||||
if (x->dir)
|
||||
l += nla_total_size(sizeof(x->dir));
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue