Skip to content

Commit a4a87fa

Browse files
antonyantonyklassert
authored andcommitted
xfrm: Add Direction to the SA in or out
This patch introduces the 'dir' attribute, 'in' or 'out', to the xfrm_state, SA, enhancing usability by delineating the scope of values based on direction. An input SA will restrict values pertinent to input, effectively segregating them from output-related values. And an output SA will restrict attributes for output. This change aims to streamline the configuration process and improve the overall consistency of SA attributes during configuration. This feature sets the groundwork for future patches, including the upcoming IP-TFS patch. Signed-off-by: Antony Antony <antony.antony@secunet.com> Reviewed-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
1 parent aeb48a4 commit a4a87fa

File tree

7 files changed

+160
-9
lines changed

7 files changed

+160
-9
lines changed

include/net/xfrm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ struct xfrm_state {
291291
/* Private data of this transformer, format is opaque,
292292
* interpreted by xfrm_type methods. */
293293
void *data;
294+
u8 dir;
294295
};
295296

296297
static inline struct net *xs_net(struct xfrm_state *x)

include/uapi/linux/xfrm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ enum {
141141
XFRM_POLICY_MAX = 3
142142
};
143143

144+
enum xfrm_sa_dir {
145+
XFRM_SA_DIR_IN = 1,
146+
XFRM_SA_DIR_OUT = 2
147+
};
148+
144149
enum {
145150
XFRM_SHARE_ANY, /* No limitations */
146151
XFRM_SHARE_SESSION, /* For this session only */
@@ -315,6 +320,7 @@ enum xfrm_attr_type_t {
315320
XFRMA_SET_MARK_MASK, /* __u32 */
316321
XFRMA_IF_ID, /* __u32 */
317322
XFRMA_MTIMER_THRESH, /* __u32 in seconds for input SA */
323+
XFRMA_SA_DIR, /* __u8 */
318324
__XFRMA_MAX
319325

320326
#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */

net/xfrm/xfrm_compat.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ static const int compat_msg_min[XFRM_NR_MSGTYPES] = {
9898
};
9999

100100
static const struct nla_policy compat_policy[XFRMA_MAX+1] = {
101+
[XFRMA_UNSPEC] = { .strict_start_type = XFRMA_SA_DIR },
101102
[XFRMA_SA] = { .len = XMSGSIZE(compat_xfrm_usersa_info)},
102103
[XFRMA_POLICY] = { .len = XMSGSIZE(compat_xfrm_userpolicy_info)},
103104
[XFRMA_LASTUSED] = { .type = NLA_U64},
@@ -129,6 +130,7 @@ static const struct nla_policy compat_policy[XFRMA_MAX+1] = {
129130
[XFRMA_SET_MARK_MASK] = { .type = NLA_U32 },
130131
[XFRMA_IF_ID] = { .type = NLA_U32 },
131132
[XFRMA_MTIMER_THRESH] = { .type = NLA_U32 },
133+
[XFRMA_SA_DIR] = NLA_POLICY_RANGE(NLA_U8, XFRM_SA_DIR_IN, XFRM_SA_DIR_OUT),
132134
};
133135

134136
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)
277279
case XFRMA_SET_MARK_MASK:
278280
case XFRMA_IF_ID:
279281
case XFRMA_MTIMER_THRESH:
282+
case XFRMA_SA_DIR:
280283
return xfrm_nla_cpy(dst, src, nla_len(src));
281284
default:
282-
BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
285+
BUILD_BUG_ON(XFRMA_MAX != XFRMA_SA_DIR);
283286
pr_warn_once("unsupported nla_type %d\n", src->nla_type);
284287
return -EOPNOTSUPP;
285288
}
@@ -434,7 +437,7 @@ static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla,
434437
int err;
435438

436439
if (type > XFRMA_MAX) {
437-
BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
440+
BUILD_BUG_ON(XFRMA_MAX != XFRMA_SA_DIR);
438441
NL_SET_ERR_MSG(extack, "Bad attribute");
439442
return -EOPNOTSUPP;
440443
}

net/xfrm/xfrm_device.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,12 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
253253
return -EINVAL;
254254
}
255255

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+
256262
is_packet_offload = xuo->flags & XFRM_OFFLOAD_PACKET;
257263

258264
/* We don't yet support UDP encapsulation and TFC padding. */

net/xfrm/xfrm_replay.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,8 @@ int xfrm_init_replay(struct xfrm_state *x, struct netlink_ext_ack *extack)
778778
}
779779

780780
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)) {
782783
NL_SET_ERR_MSG(extack, "ESN replay window must be > 0");
783784
return -EINVAL;
784785
}

net/xfrm/xfrm_state.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
12921292
if (km_query(x, tmpl, pol) == 0) {
12931293
spin_lock_bh(&net->xfrm.xfrm_state_lock);
12941294
x->km.state = XFRM_STATE_ACQ;
1295+
x->dir = XFRM_SA_DIR_OUT;
12951296
list_add(&x->km.all, &net->xfrm.state_all);
12961297
XFRM_STATE_INSERT(bydst, &x->bydst,
12971298
net->xfrm.state_bydst + h,
@@ -1744,6 +1745,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
17441745
x->lastused = orig->lastused;
17451746
x->new_mapping = 0;
17461747
x->new_mapping_sport = 0;
1748+
x->dir = orig->dir;
17471749

17481750
return x;
17491751

@@ -1864,8 +1866,14 @@ int xfrm_state_update(struct xfrm_state *x)
18641866
}
18651867

18661868
if (x1->km.state == XFRM_STATE_ACQ) {
1869+
if (x->dir && x1->dir != x->dir)
1870+
goto out;
1871+
18671872
__xfrm_state_insert(x);
18681873
x = NULL;
1874+
} else {
1875+
if (x1->dir != x->dir)
1876+
goto out;
18691877
}
18701878
err = 0;
18711879

net/xfrm/xfrm_user.c

Lines changed: 132 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ static inline int verify_sec_ctx_len(struct nlattr **attrs, struct netlink_ext_a
130130
}
131131

132132
static inline int verify_replay(struct xfrm_usersa_info *p,
133-
struct nlattr **attrs,
133+
struct nlattr **attrs, u8 sa_dir,
134134
struct netlink_ext_ack *extack)
135135
{
136136
struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
@@ -168,6 +168,30 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
168168
return -EINVAL;
169169
}
170170

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+
171195
return 0;
172196
}
173197

@@ -176,6 +200,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
176200
struct netlink_ext_ack *extack)
177201
{
178202
int err;
203+
u8 sa_dir = attrs[XFRMA_SA_DIR] ? nla_get_u8(attrs[XFRMA_SA_DIR]) : 0;
179204

180205
err = -EINVAL;
181206
switch (p->family) {
@@ -334,7 +359,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
334359
goto out;
335360
if ((err = verify_sec_ctx_len(attrs, extack)))
336361
goto out;
337-
if ((err = verify_replay(p, attrs, extack)))
362+
if ((err = verify_replay(p, attrs, sa_dir, extack)))
338363
goto out;
339364

340365
err = -EINVAL;
@@ -358,6 +383,77 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
358383
err = -EINVAL;
359384
goto out;
360385
}
386+
387+
if (sa_dir == XFRM_SA_DIR_OUT) {
388+
NL_SET_ERR_MSG(extack,
389+
"MTIMER_THRESH attribute should not be set on output SA");
390+
err = -EINVAL;
391+
goto out;
392+
}
393+
}
394+
395+
if (sa_dir == XFRM_SA_DIR_OUT) {
396+
if (p->flags & XFRM_STATE_DECAP_DSCP) {
397+
NL_SET_ERR_MSG(extack, "Flag DECAP_DSCP should not be set for output SA");
398+
err = -EINVAL;
399+
goto out;
400+
}
401+
402+
if (p->flags & XFRM_STATE_ICMP) {
403+
NL_SET_ERR_MSG(extack, "Flag ICMP should not be set for output SA");
404+
err = -EINVAL;
405+
goto out;
406+
}
407+
408+
if (p->flags & XFRM_STATE_WILDRECV) {
409+
NL_SET_ERR_MSG(extack, "Flag WILDRECV should not be set for output SA");
410+
err = -EINVAL;
411+
goto out;
412+
}
413+
414+
if (p->replay_window) {
415+
NL_SET_ERR_MSG(extack, "Replay window should be 0 for output SA");
416+
err = -EINVAL;
417+
goto out;
418+
}
419+
420+
if (attrs[XFRMA_REPLAY_VAL]) {
421+
struct xfrm_replay_state *replay;
422+
423+
replay = nla_data(attrs[XFRMA_REPLAY_VAL]);
424+
425+
if (replay->seq || replay->bitmap) {
426+
NL_SET_ERR_MSG(extack,
427+
"Replay seq and bitmap should be 0 for output SA");
428+
err = -EINVAL;
429+
goto out;
430+
}
431+
}
432+
}
433+
434+
if (sa_dir == XFRM_SA_DIR_IN) {
435+
if (p->flags & XFRM_STATE_NOPMTUDISC) {
436+
NL_SET_ERR_MSG(extack, "Flag NOPMTUDISC should not be set for input SA");
437+
err = -EINVAL;
438+
goto out;
439+
}
440+
441+
if (attrs[XFRMA_SA_EXTRA_FLAGS]) {
442+
u32 xflags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]);
443+
444+
if (xflags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) {
445+
NL_SET_ERR_MSG(extack, "Flag DONT_ENCAP_DSCP should not be set for input SA");
446+
err = -EINVAL;
447+
goto out;
448+
}
449+
450+
if (xflags & XFRM_SA_XFLAG_OSEQ_MAY_WRAP) {
451+
NL_SET_ERR_MSG(extack, "Flag OSEQ_MAY_WRAP should not be set for input SA");
452+
err = -EINVAL;
453+
goto out;
454+
}
455+
456+
}
361457
}
362458

363459
out:
@@ -734,6 +830,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
734830
if (attrs[XFRMA_IF_ID])
735831
x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
736832

833+
if (attrs[XFRMA_SA_DIR])
834+
x->dir = nla_get_u8(attrs[XFRMA_SA_DIR]);
835+
737836
err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV], extack);
738837
if (err)
739838
goto error;
@@ -1182,8 +1281,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
11821281
if (ret)
11831282
goto out;
11841283
}
1185-
if (x->mapping_maxage)
1284+
if (x->mapping_maxage) {
11861285
ret = nla_put_u32(skb, XFRMA_MTIMER_THRESH, x->mapping_maxage);
1286+
if (ret)
1287+
goto out;
1288+
}
1289+
if (x->dir)
1290+
ret = nla_put_u8(skb, XFRMA_SA_DIR, x->dir);
11871291
out:
11881292
return ret;
11891293
}
@@ -1618,6 +1722,9 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
16181722
if (err)
16191723
goto out;
16201724

1725+
if (attrs[XFRMA_SA_DIR])
1726+
x->dir = nla_get_u8(attrs[XFRMA_SA_DIR]);
1727+
16211728
resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
16221729
if (IS_ERR(resp_skb)) {
16231730
err = PTR_ERR(resp_skb);
@@ -2402,7 +2509,8 @@ static inline unsigned int xfrm_aevent_msgsize(struct xfrm_state *x)
24022509
+ nla_total_size_64bit(sizeof(struct xfrm_lifetime_cur))
24032510
+ nla_total_size(sizeof(struct xfrm_mark))
24042511
+ nla_total_size(4) /* XFRM_AE_RTHR */
2405-
+ nla_total_size(4); /* XFRM_AE_ETHR */
2512+
+ nla_total_size(4) /* XFRM_AE_ETHR */
2513+
+ nla_total_size(sizeof(x->dir)); /* XFRMA_SA_DIR */
24062514
}
24072515

24082516
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
24592567
if (err)
24602568
goto out_cancel;
24612569

2570+
if (x->dir) {
2571+
err = nla_put_u8(skb, XFRMA_SA_DIR, x->dir);
2572+
if (err)
2573+
goto out_cancel;
2574+
}
2575+
24622576
nlmsg_end(skb, nlh);
24632577
return 0;
24642578

@@ -3018,6 +3132,7 @@ EXPORT_SYMBOL_GPL(xfrm_msg_min);
30183132
#undef XMSGSIZE
30193133

30203134
const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
3135+
[XFRMA_UNSPEC] = { .strict_start_type = XFRMA_SA_DIR },
30213136
[XFRMA_SA] = { .len = sizeof(struct xfrm_usersa_info)},
30223137
[XFRMA_POLICY] = { .len = sizeof(struct xfrm_userpolicy_info)},
30233138
[XFRMA_LASTUSED] = { .type = NLA_U64},
@@ -3049,6 +3164,7 @@ const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
30493164
[XFRMA_SET_MARK_MASK] = { .type = NLA_U32 },
30503165
[XFRMA_IF_ID] = { .type = NLA_U32 },
30513166
[XFRMA_MTIMER_THRESH] = { .type = NLA_U32 },
3167+
[XFRMA_SA_DIR] = NLA_POLICY_RANGE(NLA_U8, XFRM_SA_DIR_IN, XFRM_SA_DIR_OUT),
30523168
};
30533169
EXPORT_SYMBOL_GPL(xfrma_policy);
30543170

@@ -3189,8 +3305,9 @@ static void xfrm_netlink_rcv(struct sk_buff *skb)
31893305

31903306
static inline unsigned int xfrm_expire_msgsize(void)
31913307
{
3192-
return NLMSG_ALIGN(sizeof(struct xfrm_user_expire))
3193-
+ nla_total_size(sizeof(struct xfrm_mark));
3308+
return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)) +
3309+
nla_total_size(sizeof(struct xfrm_mark)) +
3310+
nla_total_size(sizeof_field(struct xfrm_state, dir));
31943311
}
31953312

31963313
static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
@@ -3217,6 +3334,12 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct
32173334
if (err)
32183335
return err;
32193336

3337+
if (x->dir) {
3338+
err = nla_put_u8(skb, XFRMA_SA_DIR, x->dir);
3339+
if (err)
3340+
return err;
3341+
}
3342+
32203343
nlmsg_end(skb, nlh);
32213344
return 0;
32223345
}
@@ -3324,6 +3447,9 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x)
33243447
if (x->mapping_maxage)
33253448
l += nla_total_size(sizeof(x->mapping_maxage));
33263449

3450+
if (x->dir)
3451+
l += nla_total_size(sizeof(x->dir));
3452+
33273453
return l;
33283454
}
33293455

0 commit comments

Comments
 (0)