mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
xfrm: state: exact mark/mask match for SPI-keyed control-plane SA lookups
Add __xfrm_state_lookup_exact(); wire it into DELSA/GETSA, GETAE/NEWAE,
EXPIRE, MIGRATE_STATE. xfrm_state_update() (UPDSA) keeps wildcard match
because ALLOCSPI's larval state may be unmarked (mark 0/0), so an
exact-match UPDSA would not find it and the ADD fallback would then
fail with -EEXIST via xfrm_state_add().
Fixes: 3d6acfa764 ("xfrm: SA lookups with mark")
Signed-off-by: Antony Antony <antony.antony@secunet.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
parent
b3056e57b0
commit
6362f459bf
|
|
@ -1748,6 +1748,9 @@ struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, u32 mark,
|
|||
const xfrm_address_t *saddr,
|
||||
u8 proto,
|
||||
unsigned short family);
|
||||
struct xfrm_state *xfrm_state_lookup_exact(struct net *net, const struct xfrm_mark *mark,
|
||||
const xfrm_address_t *daddr, __be32 spi,
|
||||
u8 proto, unsigned short family);
|
||||
#ifdef CONFIG_XFRM_SUB_POLICY
|
||||
void xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n,
|
||||
unsigned short family);
|
||||
|
|
|
|||
|
|
@ -1177,11 +1177,19 @@ static struct xfrm_state *__xfrm_state_lookup_all(const struct xfrm_hash_state_p
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct xfrm_state *__xfrm_state_lookup(const struct xfrm_hash_state_ptrs *state_ptrs,
|
||||
u32 mark,
|
||||
const xfrm_address_t *daddr,
|
||||
__be32 spi, u8 proto,
|
||||
unsigned short family)
|
||||
static bool xfrm_state_mark_matches(const struct xfrm_state *x, u32 mark, u32 mask, bool exact)
|
||||
{
|
||||
if (exact)
|
||||
return x->mark.v == mark && x->mark.m == mask;
|
||||
return (mark & x->mark.m) == x->mark.v;
|
||||
}
|
||||
|
||||
static struct xfrm_state *
|
||||
__xfrm_state_lookup(const struct xfrm_hash_state_ptrs *state_ptrs,
|
||||
u32 mark, u32 mask, bool exact,
|
||||
const xfrm_address_t *daddr,
|
||||
__be32 spi, u8 proto,
|
||||
unsigned short family)
|
||||
{
|
||||
unsigned int h = __xfrm_spi_hash(daddr, spi, proto, family, state_ptrs->hmask);
|
||||
struct xfrm_state *x;
|
||||
|
|
@ -1193,7 +1201,7 @@ static struct xfrm_state *__xfrm_state_lookup(const struct xfrm_hash_state_ptrs
|
|||
!xfrm_addr_equal(&x->id.daddr, daddr, family))
|
||||
continue;
|
||||
|
||||
if ((mark & x->mark.m) != x->mark.v)
|
||||
if (!xfrm_state_mark_matches(x, mark, mask, exact))
|
||||
continue;
|
||||
if (!xfrm_state_hold_rcu(x))
|
||||
continue;
|
||||
|
|
@ -1203,6 +1211,17 @@ static struct xfrm_state *__xfrm_state_lookup(const struct xfrm_hash_state_ptrs
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct xfrm_state *
|
||||
__xfrm_state_lookup_exact(const struct xfrm_hash_state_ptrs *state_ptrs,
|
||||
const struct xfrm_mark *mark,
|
||||
const xfrm_address_t *daddr,
|
||||
__be32 spi, u8 proto,
|
||||
unsigned short family)
|
||||
{
|
||||
return __xfrm_state_lookup(state_ptrs, mark->v, mark->m, true,
|
||||
daddr, spi, proto, family);
|
||||
}
|
||||
|
||||
struct xfrm_state *xfrm_input_state_lookup(struct net *net, u32 mark,
|
||||
const xfrm_address_t *daddr,
|
||||
__be32 spi, u8 proto,
|
||||
|
|
@ -1233,7 +1252,7 @@ struct xfrm_state *xfrm_input_state_lookup(struct net *net, u32 mark,
|
|||
|
||||
xfrm_hash_ptrs_get(net, &state_ptrs);
|
||||
|
||||
x = __xfrm_state_lookup(&state_ptrs, mark, daddr, spi, proto, family);
|
||||
x = __xfrm_state_lookup(&state_ptrs, mark, 0, false, daddr, spi, proto, family);
|
||||
if (x) {
|
||||
spin_lock(&net->xfrm.xfrm_state_lock);
|
||||
if (x->km.state != XFRM_STATE_VALID) {
|
||||
|
|
@ -1283,7 +1302,7 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(const struct xfrm_hash_stat
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct xfrm_state *
|
||||
static struct xfrm_state *
|
||||
__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
|
||||
{
|
||||
struct xfrm_hash_state_ptrs state_ptrs;
|
||||
|
|
@ -1293,7 +1312,7 @@ __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
|
|||
xfrm_hash_ptrs_get(net, &state_ptrs);
|
||||
|
||||
if (use_spi)
|
||||
return __xfrm_state_lookup(&state_ptrs, mark, &x->id.daddr,
|
||||
return __xfrm_state_lookup(&state_ptrs, mark, 0, false, &x->id.daddr,
|
||||
x->id.spi, x->id.proto, family);
|
||||
else
|
||||
return __xfrm_state_lookup_byaddr(&state_ptrs, mark,
|
||||
|
|
@ -2380,7 +2399,7 @@ xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32
|
|||
rcu_read_lock();
|
||||
xfrm_hash_ptrs_get(net, &state_ptrs);
|
||||
|
||||
x = __xfrm_state_lookup(&state_ptrs, mark, daddr, spi, proto, family);
|
||||
x = __xfrm_state_lookup(&state_ptrs, mark, 0, false, daddr, spi, proto, family);
|
||||
rcu_read_unlock();
|
||||
return x;
|
||||
}
|
||||
|
|
@ -2404,6 +2423,23 @@ xfrm_state_lookup_byaddr(struct net *net, u32 mark,
|
|||
}
|
||||
EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
|
||||
|
||||
struct xfrm_state *
|
||||
xfrm_state_lookup_exact(struct net *net, const struct xfrm_mark *mark,
|
||||
const xfrm_address_t *daddr, __be32 spi,
|
||||
u8 proto, unsigned short family)
|
||||
{
|
||||
struct xfrm_hash_state_ptrs state_ptrs;
|
||||
struct xfrm_state *x;
|
||||
|
||||
rcu_read_lock();
|
||||
xfrm_hash_ptrs_get(net, &state_ptrs);
|
||||
|
||||
x = __xfrm_state_lookup_exact(&state_ptrs, mark, daddr, spi, proto, family);
|
||||
rcu_read_unlock();
|
||||
return x;
|
||||
}
|
||||
EXPORT_SYMBOL(xfrm_state_lookup_exact);
|
||||
|
||||
struct xfrm_state *
|
||||
xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid,
|
||||
u32 if_id, u32 pcpu_num, u8 proto, const xfrm_address_t *daddr,
|
||||
|
|
|
|||
|
|
@ -1109,11 +1109,12 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net,
|
|||
struct xfrm_state *x = NULL;
|
||||
struct xfrm_mark m;
|
||||
int err;
|
||||
u32 mark = xfrm_mark_get(attrs, &m);
|
||||
|
||||
xfrm_mark_get(attrs, &m);
|
||||
|
||||
if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) {
|
||||
err = -ESRCH;
|
||||
x = xfrm_state_lookup(net, mark, &p->daddr, p->spi, p->proto, p->family);
|
||||
x = xfrm_state_lookup_exact(net, &m, &p->daddr, p->spi, p->proto, p->family);
|
||||
} else {
|
||||
xfrm_address_t *saddr = NULL;
|
||||
|
||||
|
|
@ -1124,7 +1125,7 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net,
|
|||
}
|
||||
|
||||
err = -ESRCH;
|
||||
x = xfrm_state_lookup_byaddr(net, mark,
|
||||
x = xfrm_state_lookup_byaddr(net, m.v & m.m,
|
||||
&p->daddr, saddr,
|
||||
p->proto, p->family);
|
||||
}
|
||||
|
|
@ -2821,14 +2822,13 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
struct sk_buff *r_skb;
|
||||
int err;
|
||||
struct km_event c;
|
||||
u32 mark;
|
||||
struct xfrm_mark m;
|
||||
struct xfrm_aevent_id *p = nlmsg_data(nlh);
|
||||
struct xfrm_usersa_id *id = &p->sa_id;
|
||||
|
||||
mark = xfrm_mark_get(attrs, &m);
|
||||
xfrm_mark_get(attrs, &m);
|
||||
|
||||
x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family);
|
||||
x = xfrm_state_lookup_exact(net, &m, &id->daddr, id->spi, id->proto, id->family);
|
||||
if (x == NULL)
|
||||
return -ESRCH;
|
||||
|
||||
|
|
@ -2869,7 +2869,6 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
struct xfrm_state *x;
|
||||
struct km_event c;
|
||||
int err = -EINVAL;
|
||||
u32 mark = 0;
|
||||
struct xfrm_mark m;
|
||||
struct xfrm_aevent_id *p = nlmsg_data(nlh);
|
||||
struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
|
||||
|
|
@ -2889,9 +2888,10 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
return err;
|
||||
}
|
||||
|
||||
mark = xfrm_mark_get(attrs, &m);
|
||||
xfrm_mark_get(attrs, &m);
|
||||
|
||||
x = xfrm_state_lookup(net, mark, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
|
||||
x = xfrm_state_lookup_exact(net, &m, &p->sa_id.daddr, p->sa_id.spi,
|
||||
p->sa_id.proto, p->sa_id.family);
|
||||
if (x == NULL)
|
||||
return -ESRCH;
|
||||
|
||||
|
|
@ -3025,9 +3025,10 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
struct xfrm_user_expire *ue = nlmsg_data(nlh);
|
||||
struct xfrm_usersa_info *p = &ue->state;
|
||||
struct xfrm_mark m;
|
||||
u32 mark = xfrm_mark_get(attrs, &m);
|
||||
|
||||
x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family);
|
||||
xfrm_mark_get(attrs, &m);
|
||||
|
||||
x = xfrm_state_lookup_exact(net, &m, &p->id.daddr, p->id.spi, p->id.proto, p->family);
|
||||
|
||||
err = -ENOENT;
|
||||
if (x == NULL)
|
||||
|
|
@ -3402,9 +3403,9 @@ static int xfrm_do_migrate_state(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
|
||||
copy_from_user_migrate_state(&m, um);
|
||||
|
||||
x = xfrm_state_lookup(net, m.old_mark.v & m.old_mark.m,
|
||||
&um->id.daddr, um->id.spi,
|
||||
um->id.proto, um->id.family);
|
||||
x = xfrm_state_lookup_exact(net, &m.old_mark,
|
||||
&um->id.daddr, um->id.spi,
|
||||
um->id.proto, um->id.family);
|
||||
if (!x) {
|
||||
NL_SET_ERR_MSG(extack, "Can not find state");
|
||||
return -ESRCH;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user