Re: nftables: oob crash w. verdict maps & jumps

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

 



On 14.04, Florian Westphal wrote:
> Hi.
> 
> Looks like we can memcpy more than we allocated in nft_set_elem_init().
> 
> reproducer:
> 
> nft -f /etc/nftables/ipv4-filter
> nft add map filter ipmap '{ type ipv4_addr : verdict; }'
> nft add chain filter foo
> nft add element filter ipmap { 1.2.3.4 : jump foo }
> 
> -> we scribble over elem private size
> 
> You can see this when turning on SLUB debugging and deleting the jump
> element again, we get 'Redzone overwritten'.
> 
> In nft_add_set_elem() we try to account for the length:
> 
> 3372 
> 3373         if (nla[NFTA_SET_ELEM_DATA] != NULL) {
> 3374                 err = nft_data_init(ctx, &data, sizeof(data), &d2,
> 3375                                     nla[NFTA_SET_ELEM_DATA]);
> 3376                 if (err < 0)
> 3377                         goto err2;
> [..]
>  
> 
> 3380                 if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
> 3381                         goto err3;
> 3401                 nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, d2.len);
> 3402         }
> 
> but in above 'nft add element filter ipmap { 1.2.3.4 : jump foo }'
> 
> We have dtype NFT_DATA_VERDICT, d2.len of 8, and set->dlen of 16.

Is that on x86 (32 bit)?

> So account for d2.len (8), but then later copy a size of set->dlen (16) in
> nft_set_elem_init:
> 
> 3272         if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
> 3273                 memcpy(nft_set_ext_data(ext), data, set->dlen);
> 
> Could someone please look at this?  I'm not sure what the intent is/was.
> 
> My hunch is that the check should be
> 
>  if (set->dtype != NFT_DATA_VERDICT || d2.len != set->dlen)

We actually only care about userspace provided length for data.
The verdict representation is internal, so we want to determine
the size ourselves.

> and libnftnl should also send a dlen of 16, like it already does for
> accept/drop.

I'm surprsided, because in nf_tables_newset, for verdict maps we do:

                        desc.dlen = sizeof(struct nft_verdict);

in nft_verdict_init() we do:

                desc->len = sizeof(data->verdict);

So it should work out. I don't see how we could have arrived at the
value 8.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux