@@ -5467,6 +5467,27 @@ struct nft_expr *nft_set_elem_expr_alloc(const struct nft_ctx *ctx,
54675467 return ERR_PTR (err );
54685468}
54695469
5470+ static int nft_set_ext_check (const struct nft_set_ext_tmpl * tmpl , u8 id , u32 len )
5471+ {
5472+ len += nft_set_ext_types [id ].len ;
5473+ if (len > tmpl -> ext_len [id ] ||
5474+ len > U8_MAX )
5475+ return -1 ;
5476+
5477+ return 0 ;
5478+ }
5479+
5480+ static int nft_set_ext_memcpy (const struct nft_set_ext_tmpl * tmpl , u8 id ,
5481+ void * to , const void * from , u32 len )
5482+ {
5483+ if (nft_set_ext_check (tmpl , id , len ) < 0 )
5484+ return -1 ;
5485+
5486+ memcpy (to , from , len );
5487+
5488+ return 0 ;
5489+ }
5490+
54705491void * nft_set_elem_init (const struct nft_set * set ,
54715492 const struct nft_set_ext_tmpl * tmpl ,
54725493 const u32 * key , const u32 * key_end ,
@@ -5477,17 +5498,26 @@ void *nft_set_elem_init(const struct nft_set *set,
54775498
54785499 elem = kzalloc (set -> ops -> elemsize + tmpl -> len , gfp );
54795500 if (elem == NULL )
5480- return NULL ;
5501+ return ERR_PTR ( - ENOMEM ) ;
54815502
54825503 ext = nft_set_elem_ext (set , elem );
54835504 nft_set_ext_init (ext , tmpl );
54845505
5485- if (nft_set_ext_exists (ext , NFT_SET_EXT_KEY ))
5486- memcpy (nft_set_ext_key (ext ), key , set -> klen );
5487- if (nft_set_ext_exists (ext , NFT_SET_EXT_KEY_END ))
5488- memcpy (nft_set_ext_key_end (ext ), key_end , set -> klen );
5489- if (nft_set_ext_exists (ext , NFT_SET_EXT_DATA ))
5490- memcpy (nft_set_ext_data (ext ), data , set -> dlen );
5506+ if (nft_set_ext_exists (ext , NFT_SET_EXT_KEY ) &&
5507+ nft_set_ext_memcpy (tmpl , NFT_SET_EXT_KEY ,
5508+ nft_set_ext_key (ext ), key , set -> klen ) < 0 )
5509+ goto err_ext_check ;
5510+
5511+ if (nft_set_ext_exists (ext , NFT_SET_EXT_KEY_END ) &&
5512+ nft_set_ext_memcpy (tmpl , NFT_SET_EXT_KEY_END ,
5513+ nft_set_ext_key_end (ext ), key_end , set -> klen ) < 0 )
5514+ goto err_ext_check ;
5515+
5516+ if (nft_set_ext_exists (ext , NFT_SET_EXT_DATA ) &&
5517+ nft_set_ext_memcpy (tmpl , NFT_SET_EXT_DATA ,
5518+ nft_set_ext_data (ext ), data , set -> dlen ) < 0 )
5519+ goto err_ext_check ;
5520+
54915521 if (nft_set_ext_exists (ext , NFT_SET_EXT_EXPIRATION )) {
54925522 * nft_set_ext_expiration (ext ) = get_jiffies_64 () + expiration ;
54935523 if (expiration == 0 )
@@ -5497,6 +5527,11 @@ void *nft_set_elem_init(const struct nft_set *set,
54975527 * nft_set_ext_timeout (ext ) = timeout ;
54985528
54995529 return elem ;
5530+
5531+ err_ext_check :
5532+ kfree (elem );
5533+
5534+ return ERR_PTR (- EINVAL );
55005535}
55015536
55025537static void __nft_set_elem_expr_destroy (const struct nft_ctx * ctx ,
@@ -5584,14 +5619,25 @@ int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
55845619}
55855620
55865621static int nft_set_elem_expr_setup (struct nft_ctx * ctx ,
5622+ const struct nft_set_ext_tmpl * tmpl ,
55875623 const struct nft_set_ext * ext ,
55885624 struct nft_expr * expr_array [],
55895625 u32 num_exprs )
55905626{
55915627 struct nft_set_elem_expr * elem_expr = nft_set_ext_expr (ext );
5628+ u32 len = sizeof (struct nft_set_elem_expr );
55925629 struct nft_expr * expr ;
55935630 int i , err ;
55945631
5632+ if (num_exprs == 0 )
5633+ return 0 ;
5634+
5635+ for (i = 0 ; i < num_exprs ; i ++ )
5636+ len += expr_array [i ]-> ops -> size ;
5637+
5638+ if (nft_set_ext_check (tmpl , NFT_SET_EXT_EXPRESSIONS , len ) < 0 )
5639+ return - EINVAL ;
5640+
55955641 for (i = 0 ; i < num_exprs ; i ++ ) {
55965642 expr = nft_setelem_expr_at (elem_expr , elem_expr -> size );
55975643 err = nft_expr_clone (expr , expr_array [i ]);
@@ -6054,17 +6100,23 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
60546100 }
60556101 }
60566102
6057- err = - ENOMEM ;
60586103 elem .priv = nft_set_elem_init (set , & tmpl , elem .key .val .data ,
60596104 elem .key_end .val .data , elem .data .val .data ,
60606105 timeout , expiration , GFP_KERNEL_ACCOUNT );
6061- if (elem .priv == NULL )
6106+ if (IS_ERR (elem .priv )) {
6107+ err = PTR_ERR (elem .priv );
60626108 goto err_parse_data ;
6109+ }
60636110
60646111 ext = nft_set_elem_ext (set , elem .priv );
60656112 if (flags )
60666113 * nft_set_ext_flags (ext ) = flags ;
6114+
60676115 if (ulen > 0 ) {
6116+ if (nft_set_ext_check (& tmpl , NFT_SET_EXT_USERDATA , ulen ) < 0 ) {
6117+ err = - EINVAL ;
6118+ goto err_elem_userdata ;
6119+ }
60686120 udata = nft_set_ext_userdata (ext );
60696121 udata -> len = ulen - 1 ;
60706122 nla_memcpy (& udata -> data , nla [NFTA_SET_ELEM_USERDATA ], ulen );
@@ -6073,14 +6125,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
60736125 * nft_set_ext_obj (ext ) = obj ;
60746126 obj -> use ++ ;
60756127 }
6076- err = nft_set_elem_expr_setup (ctx , ext , expr_array , num_exprs );
6128+ err = nft_set_elem_expr_setup (ctx , & tmpl , ext , expr_array , num_exprs );
60776129 if (err < 0 )
6078- goto err_elem_expr ;
6130+ goto err_elem_free ;
60796131
60806132 trans = nft_trans_elem_alloc (ctx , NFT_MSG_NEWSETELEM , set );
60816133 if (trans == NULL ) {
60826134 err = - ENOMEM ;
6083- goto err_elem_expr ;
6135+ goto err_elem_free ;
60846136 }
60856137
60866138 ext -> genmask = nft_genmask_cur (ctx -> net ) | NFT_SET_ELEM_BUSY_MASK ;
@@ -6126,10 +6178,10 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
61266178 nft_setelem_remove (ctx -> net , set , & elem );
61276179err_element_clash :
61286180 kfree (trans );
6129- err_elem_expr :
6181+ err_elem_free :
61306182 if (obj )
61316183 obj -> use -- ;
6132-
6184+ err_elem_userdata :
61336185 nf_tables_set_elem_destroy (ctx , set , elem .priv );
61346186err_parse_data :
61356187 if (nla [NFTA_SET_ELEM_DATA ] != NULL )
@@ -6311,8 +6363,10 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
63116363 elem .priv = nft_set_elem_init (set , & tmpl , elem .key .val .data ,
63126364 elem .key_end .val .data , NULL , 0 , 0 ,
63136365 GFP_KERNEL_ACCOUNT );
6314- if (elem .priv == NULL )
6366+ if (IS_ERR (elem .priv )) {
6367+ err = PTR_ERR (elem .priv );
63156368 goto fail_elem_key_end ;
6369+ }
63166370
63176371 ext = nft_set_elem_ext (set , elem .priv );
63186372 if (flags )
0 commit comments