@@ -2496,13 +2496,56 @@ static inline int add_nested_action_start(struct sw_flow_actions **sfa,
24962496 return used ;
24972497}
24982498
2499- static inline void add_nested_action_end (struct sw_flow_actions * sfa ,
2500- int st_offset )
2499+ static inline int add_nested_action_end (struct sw_flow_actions * sfa ,
2500+ int st_offset )
25012501{
2502- struct nlattr * a = (struct nlattr * ) ((unsigned char * )sfa -> actions +
2503- st_offset );
2502+ struct nlattr * a ;
2503+ u32 attr_len ;
2504+
2505+ if (WARN_ON_ONCE (st_offset < 0 ||
2506+ (u32 )st_offset > sfa -> actions_len ))
2507+ return - EINVAL ;
2508+
2509+ attr_len = sfa -> actions_len - (u32 )st_offset ;
2510+ if (WARN_ON_ONCE (attr_len < NLA_HDRLEN ))
2511+ return - EINVAL ;
25042512
2505- a -> nla_len = sfa -> actions_len - st_offset ;
2513+ if (attr_len > U16_MAX )
2514+ return - EMSGSIZE ;
2515+
2516+ a = (struct nlattr * )((u8 * )sfa -> actions + st_offset );
2517+ a -> nla_len = attr_len ;
2518+ return 0 ;
2519+ }
2520+
2521+ /* Free the generated action-list tail at @start and truncate it.
2522+ * If @nested, @start points to its containing nlattr header.
2523+ */
2524+ static void ovs_nla_trim (struct sw_flow_actions * sfa , int start , bool nested )
2525+ {
2526+ const struct nlattr * actions ;
2527+ u32 len ;
2528+
2529+ if (start < 0 )
2530+ return ;
2531+
2532+ if (WARN_ON_ONCE ((u32 )start > sfa -> actions_len ))
2533+ return ;
2534+
2535+ actions = (const struct nlattr * )((u8 * )sfa -> actions + start );
2536+ len = sfa -> actions_len - (u32 )start ;
2537+
2538+ if (nested ) {
2539+ if (len < NLA_HDRLEN )
2540+ goto out ;
2541+
2542+ actions = (const struct nlattr * )((u8 * )actions + NLA_HDRLEN );
2543+ len -= NLA_HDRLEN ;
2544+ }
2545+
2546+ ovs_nla_free_nested_actions (actions , len );
2547+ out :
2548+ sfa -> actions_len = start ;
25062549}
25072550
25082551static int __ovs_nla_copy_actions (struct net * net , const struct nlattr * attr ,
@@ -2522,6 +2565,7 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
25222565 const struct nlattr * attrs [OVS_SAMPLE_ATTR_MAX + 1 ];
25232566 const struct nlattr * probability , * actions ;
25242567 const struct nlattr * a ;
2568+ int actions_start ;
25252569 int rem , start , err ;
25262570 struct sample_arg arg ;
25272571
@@ -2565,18 +2609,27 @@ static int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
25652609 err = ovs_nla_add_action (sfa , OVS_SAMPLE_ATTR_ARG , & arg , sizeof (arg ),
25662610 log );
25672611 if (err )
2568- return err ;
2612+ goto err ;
25692613
2614+ actions_start = (* sfa )-> actions_len ;
25702615 err = __ovs_nla_copy_actions (net , actions , key , sfa ,
25712616 eth_type , vlan_tci , mpls_label_count , log ,
25722617 depth + 1 );
25732618
25742619 if (err )
2575- return err ;
2620+ goto err_free ;
25762621
2577- add_nested_action_end (* sfa , start );
2622+ err = add_nested_action_end (* sfa , start );
2623+ if (err )
2624+ goto err_free ;
25782625
25792626 return 0 ;
2627+
2628+ err_free :
2629+ ovs_nla_trim (* sfa , actions_start , false);
2630+ err :
2631+ (* sfa )-> actions_len = start ;
2632+ return err ;
25802633}
25812634
25822635static int validate_and_copy_dec_ttl (struct net * net ,
@@ -2624,18 +2677,31 @@ static int validate_and_copy_dec_ttl(struct net *net,
26242677 return start ;
26252678
26262679 action_start = add_nested_action_start (sfa , OVS_DEC_TTL_ATTR_ACTION , log );
2627- if (action_start < 0 )
2628- return action_start ;
2680+ if (action_start < 0 ) {
2681+ err = action_start ;
2682+ goto err ;
2683+ }
26292684
26302685 err = __ovs_nla_copy_actions (net , actions , key , sfa , eth_type ,
26312686 vlan_tci , mpls_label_count , log ,
26322687 depth + 1 );
26332688 if (err )
2634- return err ;
2689+ goto err_free ;
2690+
2691+ err = add_nested_action_end (* sfa , action_start );
2692+ if (err )
2693+ goto err_free ;
26352694
2636- add_nested_action_end (* sfa , action_start );
2637- add_nested_action_end (* sfa , start );
2695+ err = add_nested_action_end (* sfa , start );
2696+ if (err )
2697+ goto err_free ;
26382698 return 0 ;
2699+
2700+ err_free :
2701+ ovs_nla_trim (* sfa , action_start , true);
2702+ err :
2703+ (* sfa )-> actions_len = start ;
2704+ return err ;
26392705}
26402706
26412707static int validate_and_copy_clone (struct net * net ,
@@ -2646,6 +2712,7 @@ static int validate_and_copy_clone(struct net *net,
26462712 u32 mpls_label_count , bool log , bool last ,
26472713 u32 depth )
26482714{
2715+ int actions_start ;
26492716 int start , err ;
26502717 u32 exec ;
26512718
@@ -2661,17 +2728,26 @@ static int validate_and_copy_clone(struct net *net,
26612728 err = ovs_nla_add_action (sfa , OVS_CLONE_ATTR_EXEC , & exec ,
26622729 sizeof (exec ), log );
26632730 if (err )
2664- return err ;
2731+ goto err ;
26652732
2733+ actions_start = (* sfa )-> actions_len ;
26662734 err = __ovs_nla_copy_actions (net , attr , key , sfa ,
26672735 eth_type , vlan_tci , mpls_label_count , log ,
26682736 depth + 1 );
26692737 if (err )
2670- return err ;
2738+ goto err_free ;
26712739
2672- add_nested_action_end (* sfa , start );
2740+ err = add_nested_action_end (* sfa , start );
2741+ if (err )
2742+ goto err_free ;
26732743
26742744 return 0 ;
2745+
2746+ err_free :
2747+ ovs_nla_trim (* sfa , actions_start , false);
2748+ err :
2749+ (* sfa )-> actions_len = start ;
2750+ return err ;
26752751}
26762752
26772753void ovs_match_init (struct sw_flow_match * match ,
@@ -2763,20 +2839,20 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
27632839 tun_dst = metadata_dst_alloc (key .tun_opts_len , METADATA_IP_TUNNEL ,
27642840 GFP_KERNEL );
27652841
2766- if (!tun_dst )
2767- return - ENOMEM ;
2842+ if (!tun_dst ) {
2843+ err = - ENOMEM ;
2844+ goto err ;
2845+ }
27682846
27692847 err = dst_cache_init (& tun_dst -> u .tun_info .dst_cache , GFP_KERNEL );
2770- if (err ) {
2771- dst_release ((struct dst_entry * )tun_dst );
2772- return err ;
2773- }
2848+ if (err )
2849+ goto err_free_tun_dst ;
27742850
27752851 a = __add_action (sfa , OVS_KEY_ATTR_TUNNEL_INFO , NULL ,
27762852 sizeof (* ovs_tun ), log );
27772853 if (IS_ERR (a )) {
2778- dst_release (( struct dst_entry * ) tun_dst );
2779- return PTR_ERR ( a ) ;
2854+ err = PTR_ERR ( a );
2855+ goto err_free_tun_dst ;
27802856 }
27812857
27822858 ovs_tun = nla_data (a );
@@ -2797,8 +2873,16 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
27972873 ip_tunnel_info_opts_set (tun_info ,
27982874 TUN_METADATA_OPTS (& key , key .tun_opts_len ),
27992875 key .tun_opts_len , dst_opt_type );
2800- add_nested_action_end (* sfa , start );
2876+ err = add_nested_action_end (* sfa , start );
2877+ if (WARN_ON_ONCE (err ))
2878+ goto err_free_tun_dst ;
2879+
2880+ return 0 ;
28012881
2882+ err_free_tun_dst :
2883+ dst_release ((struct dst_entry * )tun_dst );
2884+ err :
2885+ (* sfa )-> actions_len = start ;
28022886 return err ;
28032887}
28042888
@@ -2971,7 +3055,7 @@ static int validate_set(const struct nlattr *a,
29713055
29723056 /* Convert non-masked non-tunnel set actions to masked set actions. */
29733057 if (!masked && key_type != OVS_KEY_ATTR_TUNNEL ) {
2974- int start , len = key_len * 2 ;
3058+ int err , start , len = key_len * 2 ;
29753059 struct nlattr * at ;
29763060
29773061 * skip_copy = true;
@@ -2983,8 +3067,11 @@ static int validate_set(const struct nlattr *a,
29833067 return start ;
29843068
29853069 at = __add_action (sfa , key_type , NULL , len , log );
2986- if (IS_ERR (at ))
2987- return PTR_ERR (at );
3070+ if (IS_ERR (at )) {
3071+ err = PTR_ERR (at );
3072+ (* sfa )-> actions_len = start ;
3073+ return err ;
3074+ }
29883075
29893076 memcpy (nla_data (at ), nla_data (ovs_key ), key_len ); /* Key. */
29903077 memset (nla_data (at ) + key_len , 0xff , key_len ); /* Mask. */
@@ -2994,7 +3081,11 @@ static int validate_set(const struct nlattr *a,
29943081
29953082 mask -> ipv6_label &= htonl (0x000FFFFF );
29963083 }
2997- add_nested_action_end (* sfa , start );
3084+ err = add_nested_action_end (* sfa , start );
3085+ if (WARN_ON_ONCE (err )) {
3086+ (* sfa )-> actions_len = start ;
3087+ return err ;
3088+ }
29983089 }
29993090
30003091 return 0 ;
@@ -3040,7 +3131,8 @@ static int validate_and_copy_check_pkt_len(struct net *net,
30403131 const struct nlattr * acts_if_greater , * acts_if_lesser_eq ;
30413132 struct nlattr * a [OVS_CHECK_PKT_LEN_ATTR_MAX + 1 ];
30423133 struct check_pkt_len_arg arg ;
3043- int nested_acts_start ;
3134+ int greater_acts_start = -1 ;
3135+ int lesser_acts_start = -1 ;
30443136 int start , err ;
30453137
30463138 err = nla_parse_deprecated_strict (a , OVS_CHECK_PKT_LEN_ATTR_MAX ,
@@ -3075,37 +3167,58 @@ static int validate_and_copy_check_pkt_len(struct net *net,
30753167 err = ovs_nla_add_action (sfa , OVS_CHECK_PKT_LEN_ATTR_ARG , & arg ,
30763168 sizeof (arg ), log );
30773169 if (err )
3078- return err ;
3170+ goto err_free ;
30793171
3080- nested_acts_start = add_nested_action_start (sfa ,
3081- OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL , log );
3082- if (nested_acts_start < 0 )
3083- return nested_acts_start ;
3172+ lesser_acts_start =
3173+ add_nested_action_start (sfa ,
3174+ OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL ,
3175+ log );
3176+ if (lesser_acts_start < 0 ) {
3177+ err = lesser_acts_start ;
3178+ goto err_free ;
3179+ }
30843180
30853181 err = __ovs_nla_copy_actions (net , acts_if_lesser_eq , key , sfa ,
30863182 eth_type , vlan_tci , mpls_label_count , log ,
30873183 depth + 1 );
30883184
30893185 if (err )
3090- return err ;
3186+ goto err_free ;
30913187
3092- add_nested_action_end (* sfa , nested_acts_start );
3188+ err = add_nested_action_end (* sfa , lesser_acts_start );
3189+ if (err )
3190+ goto err_free ;
30933191
3094- nested_acts_start = add_nested_action_start (sfa ,
3095- OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER , log );
3096- if (nested_acts_start < 0 )
3097- return nested_acts_start ;
3192+ greater_acts_start =
3193+ add_nested_action_start (sfa ,
3194+ OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER ,
3195+ log );
3196+ if (greater_acts_start < 0 ) {
3197+ err = greater_acts_start ;
3198+ goto err_free ;
3199+ }
30983200
30993201 err = __ovs_nla_copy_actions (net , acts_if_greater , key , sfa ,
31003202 eth_type , vlan_tci , mpls_label_count , log ,
31013203 depth + 1 );
31023204
31033205 if (err )
3104- return err ;
3206+ goto err_free ;
3207+
3208+ err = add_nested_action_end (* sfa , greater_acts_start );
3209+ if (err )
3210+ goto err_free ;
31053211
3106- add_nested_action_end (* sfa , nested_acts_start );
3107- add_nested_action_end (* sfa , start );
3212+ err = add_nested_action_end (* sfa , start );
3213+ if (err )
3214+ goto err_free ;
31083215 return 0 ;
3216+
3217+ err_free :
3218+ ovs_nla_trim (* sfa , greater_acts_start , true);
3219+ ovs_nla_trim (* sfa , lesser_acts_start , true);
3220+ ovs_nla_trim (* sfa , start , false);
3221+ return err ;
31093222}
31103223
31113224static int validate_psample (const struct nlattr * attr )
0 commit comments