@@ -6706,7 +6706,8 @@ static void nft_trans_set_elem_destroy(const struct nft_ctx *ctx, struct nft_tra
67066706 int i ;
67076707
67086708 for (i = 0 ; i < te -> nelems ; i ++ ) {
6709- if (te -> elems [i ].update_flags )
6709+ /* skip update request, see nft_trans_elems_new_abort() */
6710+ if (!te -> elems [i ].priv )
67106711 continue ;
67116712
67126713 __nft_set_elem_destroy (ctx , te -> set , te -> elems [i ].priv , true);
@@ -6897,12 +6898,13 @@ static void nft_trans_elem_update(const struct nft_set *set,
68976898 const struct nft_trans_one_elem * elem )
68986899{
68996900 const struct nft_set_ext * ext = nft_set_elem_ext (set , elem -> priv );
6901+ const struct nft_elem_update * update = elem -> update ;
69006902
6901- if (elem -> update_flags & NFT_TRANS_UPD_TIMEOUT )
6902- WRITE_ONCE (nft_set_ext_timeout (ext )-> timeout , elem -> timeout );
6903+ if (update -> flags & NFT_TRANS_UPD_TIMEOUT )
6904+ WRITE_ONCE (nft_set_ext_timeout (ext )-> timeout , update -> timeout );
69036905
6904- if (elem -> update_flags & NFT_TRANS_UPD_EXPIRATION )
6905- WRITE_ONCE (nft_set_ext_timeout (ext )-> expiration , get_jiffies_64 () + elem -> expiration );
6906+ if (update -> flags & NFT_TRANS_UPD_EXPIRATION )
6907+ WRITE_ONCE (nft_set_ext_timeout (ext )-> expiration , get_jiffies_64 () + update -> expiration );
69066908}
69076909
69086910static void nft_trans_elems_add (const struct nft_ctx * ctx ,
@@ -6911,15 +6913,16 @@ static void nft_trans_elems_add(const struct nft_ctx *ctx,
69116913 int i ;
69126914
69136915 for (i = 0 ; i < te -> nelems ; i ++ ) {
6914- const struct nft_trans_one_elem * elem = & te -> elems [i ];
6916+ struct nft_trans_one_elem * elem = & te -> elems [i ];
69156917
6916- if (elem -> update_flags )
6918+ if (elem -> update )
69176919 nft_trans_elem_update (te -> set , elem );
69186920 else
69196921 nft_setelem_activate (ctx -> net , te -> set , elem -> priv );
69206922
69216923 nf_tables_setelem_notify (ctx , te -> set , elem -> priv ,
69226924 NFT_MSG_NEWSETELEM );
6925+ kfree (elem -> update );
69236926 }
69246927}
69256928
@@ -7011,6 +7014,8 @@ static void nft_trans_elems_remove(const struct nft_ctx *ctx,
70117014 int i ;
70127015
70137016 for (i = 0 ; i < te -> nelems ; i ++ ) {
7017+ WARN_ON_ONCE (te -> elems [i ].update );
7018+
70147019 nf_tables_setelem_notify (ctx , te -> set ,
70157020 te -> elems [i ].priv ,
70167021 te -> nft_trans .msg_type );
@@ -7059,7 +7064,6 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
70597064 struct nft_data_desc desc ;
70607065 enum nft_registers dreg ;
70617066 struct nft_trans * trans ;
7062- u8 update_flags ;
70637067 u64 expiration ;
70647068 u64 timeout ;
70657069 int err , i ;
@@ -7374,26 +7378,32 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
73747378 else if (!(nlmsg_flags & NLM_F_EXCL )) {
73757379 err = 0 ;
73767380 if (nft_set_ext_exists (ext2 , NFT_SET_EXT_TIMEOUT )) {
7377- struct nft_trans_one_elem * update ;
7378-
7379- update = & nft_trans_container_elem (trans )-> elems [0 ];
7381+ struct nft_elem_update update = { };
73807382
7381- update_flags = 0 ;
73827383 if (timeout != nft_set_ext_timeout (ext2 )-> timeout ) {
7383- update -> timeout = timeout ;
7384+ update . timeout = timeout ;
73847385 if (expiration == 0 )
73857386 expiration = timeout ;
73867387
7387- update_flags |= NFT_TRANS_UPD_TIMEOUT ;
7388+ update . flags |= NFT_TRANS_UPD_TIMEOUT ;
73887389 }
73897390 if (expiration ) {
7390- update -> expiration = expiration ;
7391- update_flags |= NFT_TRANS_UPD_EXPIRATION ;
7391+ update . expiration = expiration ;
7392+ update . flags |= NFT_TRANS_UPD_EXPIRATION ;
73927393 }
73937394
7394- if (update_flags ) {
7395- update -> priv = elem_priv ;
7396- update -> update_flags = update_flags ;
7395+ if (update .flags ) {
7396+ struct nft_trans_one_elem * ue ;
7397+
7398+ ue = & nft_trans_container_elem (trans )-> elems [0 ];
7399+
7400+ ue -> update = kmemdup (& update , sizeof (update ), GFP_KERNEL );
7401+ if (!ue -> update ) {
7402+ err = - ENOMEM ;
7403+ goto err_element_clash ;
7404+ }
7405+
7406+ ue -> priv = elem_priv ;
73977407 nft_trans_commit_list_add_elem (ctx -> net , trans , GFP_KERNEL );
73987408 goto err_elem_free ;
73997409 }
@@ -7561,14 +7571,19 @@ void nft_setelem_data_deactivate(const struct net *net,
75617571 * Returns true if set had been added to (i.e., elements need to be removed again).
75627572 */
75637573static bool nft_trans_elems_new_abort (const struct nft_ctx * ctx ,
7564- const struct nft_trans_elem * te )
7574+ struct nft_trans_elem * te )
75657575{
75667576 bool removed = false;
75677577 int i ;
75687578
75697579 for (i = 0 ; i < te -> nelems ; i ++ ) {
7570- if (te -> elems [i ].update_flags )
7580+ if (te -> elems [i ].update ) {
7581+ kfree (te -> elems [i ].update );
7582+ te -> elems [i ].update = NULL ;
7583+ /* Update request, so do not release this element */
7584+ te -> elems [i ].priv = NULL ;
75717585 continue ;
7586+ }
75727587
75737588 if (!te -> set -> ops -> abort || nft_setelem_is_catchall (te -> set , te -> elems [i ].priv ))
75747589 nft_setelem_remove (ctx -> net , te -> set , te -> elems [i ].priv );
0 commit comments