@@ -130,7 +130,7 @@ static inline int verify_sec_ctx_len(struct nlattr **attrs, struct netlink_ext_a
130130}
131131
132132static 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
363459out :
@@ -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 );
11871291out :
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
24082516static 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
30203134const 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};
30533169EXPORT_SYMBOL_GPL (xfrma_policy );
30543170
@@ -3189,8 +3305,9 @@ static void xfrm_netlink_rcv(struct sk_buff *skb)
31893305
31903306static 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
31963313static 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