Re: [PATCH nf] netfilter: nf_tables: fix set double-free in abort path

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Mar 08, 2019 at 11:22:17AM +0100, Florian Westphal wrote:
> Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> wrote:
> > So the problem is only the use-after-free from the NEWSETELEM abort
> > path, right?
> 
> That and the double-freeing of the set.
> 
> > Probably we can fix this problem with this patch too? Idea is to keep
> > this 'bound' internal flag, in that case, this turns the NEWSET and
> > NEWSETELEM abort path into noop.
> 
> Good idea, but your patch still causes UAF.
> 
> > @@ -6617,10 +6617,13 @@ static void nf_tables_abort_release(struct nft_trans *trans)
> >  		nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
> >  		break;
> >  	case NFT_MSG_NEWSET:
> > -		if (!nft_trans_set_bound(trans))
> > -			nft_set_destroy(nft_trans_set(trans));
> > +		if (nft_trans_set(trans)->bound)
> > +			break;
> > +		nft_set_destroy(nft_trans_set(trans));
> 
> Its not safe to use nft_trans_set() here anymore, as the set
> has already been released by nf_tables_rule_destroy().

Oh, right.

> >  	case NFT_MSG_NEWSETELEM:
> > +		if (nft_trans_elem_set(trans)->bound)
> > +			break;
> 
> Same here.
> 
> Either the transactions themselves need to be yanked here, before
> nf_tables_abort_release() is run, or the 'bound' flag needs to be
> stored in the transaction struct.
>
> I'd guess nft_trans_delete() is enough instead of plain break,
> in case the set is bound we know expr destructor removes the set,
> and if we avoid removal of the elements then those are removed too
> when the set is destroyed.
> 
> This seems to make things work for me, on top of your patch:

That looks good, I'm going to collapse it to my patch and resend.

Thanks.

> diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
> --- a/net/netfilter/nf_tables_api.c
> +++ b/net/netfilter/nf_tables_api.c
> @@ -6786,8 +6786,10 @@ static int __nf_tables_abort(struct net *net)
>  			break;
>  		case NFT_MSG_NEWSET:
>  			trans->ctx.table->use--;
> -			if (nft_trans_set(trans)->bound)
> +			if (nft_trans_set(trans)->bound) {
> +				nft_trans_destroy(trans);
>  				break;
> +			}
>  			list_del_rcu(&nft_trans_set(trans)->list);
>  			break;
>  		case NFT_MSG_DELSET:
> @@ -6796,8 +6798,10 @@ static int __nf_tables_abort(struct net *net)
>  			nft_trans_destroy(trans);
>  			break;
>  		case NFT_MSG_NEWSETELEM:
> -			if (nft_trans_elem_set(trans)->bound)
> +			if (nft_trans_elem_set(trans)->bound) {
> +				nft_trans_destroy(trans);
>  				break;
> +			}
>  			te = (struct nft_trans_elem *)trans->data;
>  			te->set->ops->remove(net, te->set, &te->elem);
>  			atomic_dec(&te->set->nelems);



[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux