@@ -5686,6 +5686,27 @@ struct nft_expr *nft_set_elem_expr_alloc(const struct nft_ctx *ctx,
56865686 return ERR_PTR (err );
56875687}
56885688
5689+ static int nft_set_ext_check (const struct nft_set_ext_tmpl * tmpl , u8 id , u32 len )
5690+ {
5691+ len += nft_set_ext_types [id ].len ;
5692+ if (len > tmpl -> ext_len [id ] ||
5693+ len > U8_MAX )
5694+ return -1 ;
5695+
5696+ return 0 ;
5697+ }
5698+
5699+ static int nft_set_ext_memcpy (const struct nft_set_ext_tmpl * tmpl , u8 id ,
5700+ void * to , const void * from , u32 len )
5701+ {
5702+ if (nft_set_ext_check (tmpl , id , len ) < 0 )
5703+ return -1 ;
5704+
5705+ memcpy (to , from , len );
5706+
5707+ return 0 ;
5708+ }
5709+
56895710void * nft_set_elem_init (const struct nft_set * set ,
56905711 const struct nft_set_ext_tmpl * tmpl ,
56915712 const u32 * key , const u32 * key_end ,
@@ -5696,17 +5717,26 @@ void *nft_set_elem_init(const struct nft_set *set,
56965717
56975718 elem = kzalloc (set -> ops -> elemsize + tmpl -> len , gfp );
56985719 if (elem == NULL )
5699- return NULL ;
5720+ return ERR_PTR ( - ENOMEM ) ;
57005721
57015722 ext = nft_set_elem_ext (set , elem );
57025723 nft_set_ext_init (ext , tmpl );
57035724
5704- if (nft_set_ext_exists (ext , NFT_SET_EXT_KEY ))
5705- memcpy (nft_set_ext_key (ext ), key , set -> klen );
5706- if (nft_set_ext_exists (ext , NFT_SET_EXT_KEY_END ))
5707- memcpy (nft_set_ext_key_end (ext ), key_end , set -> klen );
5708- if (nft_set_ext_exists (ext , NFT_SET_EXT_DATA ))
5709- memcpy (nft_set_ext_data (ext ), data , set -> dlen );
5725+ if (nft_set_ext_exists (ext , NFT_SET_EXT_KEY ) &&
5726+ nft_set_ext_memcpy (tmpl , NFT_SET_EXT_KEY ,
5727+ nft_set_ext_key (ext ), key , set -> klen ) < 0 )
5728+ goto err_ext_check ;
5729+
5730+ if (nft_set_ext_exists (ext , NFT_SET_EXT_KEY_END ) &&
5731+ nft_set_ext_memcpy (tmpl , NFT_SET_EXT_KEY_END ,
5732+ nft_set_ext_key_end (ext ), key_end , set -> klen ) < 0 )
5733+ goto err_ext_check ;
5734+
5735+ if (nft_set_ext_exists (ext , NFT_SET_EXT_DATA ) &&
5736+ nft_set_ext_memcpy (tmpl , NFT_SET_EXT_DATA ,
5737+ nft_set_ext_data (ext ), data , set -> dlen ) < 0 )
5738+ goto err_ext_check ;
5739+
57105740 if (nft_set_ext_exists (ext , NFT_SET_EXT_EXPIRATION )) {
57115741 * nft_set_ext_expiration (ext ) = get_jiffies_64 () + expiration ;
57125742 if (expiration == 0 )
@@ -5716,6 +5746,11 @@ void *nft_set_elem_init(const struct nft_set *set,
57165746 * nft_set_ext_timeout (ext ) = timeout ;
57175747
57185748 return elem ;
5749+
5750+ err_ext_check :
5751+ kfree (elem );
5752+
5753+ return ERR_PTR (- EINVAL );
57195754}
57205755
57215756static void __nft_set_elem_expr_destroy (const struct nft_ctx * ctx ,
@@ -5803,14 +5838,25 @@ int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
58035838}
58045839
58055840static int nft_set_elem_expr_setup (struct nft_ctx * ctx ,
5841+ const struct nft_set_ext_tmpl * tmpl ,
58065842 const struct nft_set_ext * ext ,
58075843 struct nft_expr * expr_array [],
58085844 u32 num_exprs )
58095845{
58105846 struct nft_set_elem_expr * elem_expr = nft_set_ext_expr (ext );
5847+ u32 len = sizeof (struct nft_set_elem_expr );
58115848 struct nft_expr * expr ;
58125849 int i , err ;
58135850
5851+ if (num_exprs == 0 )
5852+ return 0 ;
5853+
5854+ for (i = 0 ; i < num_exprs ; i ++ )
5855+ len += expr_array [i ]-> ops -> size ;
5856+
5857+ if (nft_set_ext_check (tmpl , NFT_SET_EXT_EXPRESSIONS , len ) < 0 )
5858+ return - EINVAL ;
5859+
58145860 for (i = 0 ; i < num_exprs ; i ++ ) {
58155861 expr = nft_setelem_expr_at (elem_expr , elem_expr -> size );
58165862 err = nft_expr_clone (expr , expr_array [i ]);
@@ -6304,17 +6350,23 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
63046350 }
63056351 }
63066352
6307- err = - ENOMEM ;
63086353 elem .priv = nft_set_elem_init (set , & tmpl , elem .key .val .data ,
63096354 elem .key_end .val .data , elem .data .val .data ,
63106355 timeout , expiration , GFP_KERNEL );
6311- if (elem .priv == NULL )
6356+ if (IS_ERR (elem .priv )) {
6357+ err = PTR_ERR (elem .priv );
63126358 goto err_parse_data ;
6359+ }
63136360
63146361 ext = nft_set_elem_ext (set , elem .priv );
63156362 if (flags )
63166363 * nft_set_ext_flags (ext ) = flags ;
6364+
63176365 if (ulen > 0 ) {
6366+ if (nft_set_ext_check (& tmpl , NFT_SET_EXT_USERDATA , ulen ) < 0 ) {
6367+ err = - EINVAL ;
6368+ goto err_elem_userdata ;
6369+ }
63186370 udata = nft_set_ext_userdata (ext );
63196371 udata -> len = ulen - 1 ;
63206372 nla_memcpy (& udata -> data , nla [NFTA_SET_ELEM_USERDATA ], ulen );
@@ -6323,14 +6375,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
63236375 * nft_set_ext_obj (ext ) = obj ;
63246376 obj -> use ++ ;
63256377 }
6326- err = nft_set_elem_expr_setup (ctx , ext , expr_array , num_exprs );
6378+ err = nft_set_elem_expr_setup (ctx , & tmpl , ext , expr_array , num_exprs );
63276379 if (err < 0 )
6328- goto err_elem_expr ;
6380+ goto err_elem_free ;
63296381
63306382 trans = nft_trans_elem_alloc (ctx , NFT_MSG_NEWSETELEM , set );
63316383 if (trans == NULL ) {
63326384 err = - ENOMEM ;
6333- goto err_elem_expr ;
6385+ goto err_elem_free ;
63346386 }
63356387
63366388 ext -> genmask = nft_genmask_cur (ctx -> net ) | NFT_SET_ELEM_BUSY_MASK ;
@@ -6376,10 +6428,10 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
63766428 nft_setelem_remove (ctx -> net , set , & elem );
63776429err_element_clash :
63786430 kfree (trans );
6379- err_elem_expr :
6431+ err_elem_free :
63806432 if (obj )
63816433 obj -> use -- ;
6382-
6434+ err_elem_userdata :
63836435 nf_tables_set_elem_destroy (ctx , set , elem .priv );
63846436err_parse_data :
63856437 if (nla [NFTA_SET_ELEM_DATA ] != NULL )
@@ -6554,8 +6606,10 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
65546606 elem .priv = nft_set_elem_init (set , & tmpl , elem .key .val .data ,
65556607 elem .key_end .val .data , NULL , 0 , 0 ,
65566608 GFP_KERNEL );
6557- if (elem .priv == NULL )
6609+ if (IS_ERR (elem .priv )) {
6610+ err = PTR_ERR (elem .priv );
65586611 goto fail_elem_key_end ;
6612+ }
65596613
65606614 ext = nft_set_elem_ext (set , elem .priv );
65616615 if (flags )
0 commit comments