All of lore.kernel.org
 help / color / mirror / Atom feed
From: Phil Sutter <phil@nwl.cc>
To: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: netfilter-devel@vger.kernel.org
Subject: Re: [libnftnl PATCH] src: Fix nftnl_assert() on data_len
Date: Tue, 18 Feb 2020 19:18:51 +0100	[thread overview]
Message-ID: <20200218181851.GC20005@orbyte.nwl.cc> (raw)
In-Reply-To: <20200218134227.yndixbtxjzq3jznk@salvia>

Hi Pablo,

On Tue, Feb 18, 2020 at 02:42:27PM +0100, Pablo Neira Ayuso wrote:
> On Sat, Feb 15, 2020 at 11:58:55PM +0100, Phil Sutter wrote:
> > On Sat, Feb 15, 2020 at 02:17:13PM +0100, Pablo Neira Ayuso wrote:
> > > On Sat, Feb 15, 2020 at 01:43:11AM +0100, Phil Sutter wrote:
> > > > On Fri, Feb 14, 2020 at 06:42:00PM +0100, Pablo Neira Ayuso wrote:
> > > > > On Fri, Feb 14, 2020 at 06:34:50PM +0100, Phil Sutter wrote:
> > > > > > On Fri, Feb 14, 2020 at 06:32:47PM +0100, Pablo Neira Ayuso wrote:
> > > > > > > On Fri, Feb 14, 2020 at 06:24:17PM +0100, Phil Sutter wrote:
> > > > > > > > Typical idiom for *_get_u*() getters is to call *_get_data() and make
> > > > > > > > sure data_len matches what each of them is returning. Yet they shouldn't
> > > > > > > > trust *_get_data() to write into passed pointer to data_len since for
> > > > > > > > chains and NFTNL_CHAIN_DEVICES attribute, it does not. Make sure these
> > > > > > > > assert() calls trigger in those cases.
> > > > > > > 
> > > > > > > The intention to catch for unset attributes through the assertion,
> > > > > > > right?
> > > > > > 
> > > > > > No, this is about making sure that no wrong getter is called, e.g.
> > > > > > nftnl_chain_get_u64() with e.g. NFTNL_CHAIN_HOOKNUM attribute which is
> > > > > > only 32bits.
> > > > > 
> > > > > I think it will also catch the case I'm asking. If attribute is unset,
> > > > > then nftnl_chain_get_data() returns NULL and the assertion checks
> > > > > data_len, which has not been properly initialized.
> > > > 
> > > > With nftnl_assert() being (shortened):
> > > > 
> > > > | #define nftnl_assert(val, attr, expr) \
> > > > |  ((!val || expr) ? \
> > > > |  (void)0 : __nftnl_assert_fail(attr, __FILE__, __LINE__))
> > > > 
> > > > Check for 'expr' (which is passed as 'data_len == sizeof(<something>)')
> > > > will only happen if 'val' is not NULL. Callers then return like so:
> > > > 
> > > > | return val ? *val : 0;
> > > > 
> > > > This means that if you pass an unset attribute to the getter, it will
> > > > simply return 0.
> > > 
> > > Thanks for explaining, Phil. If the problem is just
> > > NFTNL_CHAIN_DEVICES and NFTNL_FLOWTABLE_DEVICES, probably this is just
> > > fine? So zero data-length is reversed for arrays and update
> > > nftnl_assert() to skip data_len == 0, ie.
> > > 
> > > > | #define nftnl_assert(val, attr, expr) \
> > > > |  ((!val || data_len == 0 || expr) ? \
> > > > |  (void)0 : __nftnl_assert_fail(attr, __FILE__, __LINE__))
> > 
> > Your proposed patch would allow to call e.g.:
> > 
> > | nftnl_chain_get_u32(c, NFTNL_CHAIN_DEVICES)
> > 
> > This would return (uint32_t)*(&c->dev_array[0]), I highly doubt we
> > should allow this. Unless I miss something, it is certainly a
> > programming error if someone calls any of the nftnl_chain_get_{u,s}*
> > getters on NFTNL_CHAIN_DEVICES attribute. So aborting with error message
> > in nftnl_assert() is not only OK but actually helpful, no?
> 
> Indeed, good point.
> 
> I don't think nftnl_flowtable_set_data() is good for these two device
> array.

Well, right now it serves as a backend for all attribute setters, and
your patch continues in that tradition. So while it may be a bit
"rustic", I'd say it's good enough for its purpose. :)

> I just sent a patch, I forgot to finish the _set_array() and
> _get_array() helpers for the flowtable, the definition in the header
> file prooves this.
> 
> Can we introduce these new interfaces? Then, update nftables to use it.
> Then, at some point, set *data_len = 0 for these array datatypes. Yes,
> it's a bit longer term, but better fix this interface. But setting all
> these data_len to zero when in most cases it is going to be thereafter
> properly set to the datatype length is...
> 
> Would this work for you? I know it is not so short term.

While I think your patch is the right way to providing a sanitized
access to the array attributes, I don't think it's really related to
what my original patch was fixing, which is:

Right now we are preventing users from passing wrong attribute types to
getters by checking the attribute length. This does not work for
NFTNL_CHAIN_DEVICES or NFTNL_FLOWTABLE_DEVICES because they don't set
data_len. Hence the expression in nftnl_asser() call:

| nftnl_assert(val, attr, data_len == sizeof(<something>));

Will lead to comparing with garbage from stack. This may in most cases
fail as expected, but there's no guarantee.

Your patch allows to use "a better" getter/setter for those problematic
attributes, but it doesn't prevent the above from happening.

My first approach was to make nftnl_chain_get_data() and
nftnl_flowtable_get_data() set:

| *data_len = 0;

for the problematic attributes, but the value is not really correct - a
"more correct" value, e.g.:

| *data_len = c->dev_array_len * sizeof(char *);

Could lead to a pass in getter sanitizing by accident although e.g.
nftnl_chain_get_u64() is completely unfit even if c->dev_array_len was
1.

So I decided to go the safe way and initialize data_len variables to zero
instead which has the benefit of catching new attributes added later as
well.

If you don't like the approach of initializing all data_len variables, I
would rather suggest to go with setting '*data_len = 0' in _get_data()
routines as described above. This has the same effect but it's just a
two lines change. What do you think?

Cheers, Phil

  reply	other threads:[~2020-02-18 18:18 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-14 17:24 [libnftnl PATCH] src: Fix nftnl_assert() on data_len Phil Sutter
2020-02-14 17:32 ` Pablo Neira Ayuso
2020-02-14 17:34   ` Phil Sutter
2020-02-14 17:42     ` Pablo Neira Ayuso
2020-02-15  0:43       ` Phil Sutter
2020-02-15 13:17         ` Pablo Neira Ayuso
2020-02-15 22:58           ` Phil Sutter
2020-02-18 13:42             ` Pablo Neira Ayuso
2020-02-18 18:18               ` Phil Sutter [this message]
2020-02-18 21:06                 ` Pablo Neira Ayuso
2020-02-18 23:02                   ` Phil Sutter
2020-02-19  9:32                     ` Pablo Neira Ayuso

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200218181851.GC20005@orbyte.nwl.cc \
    --to=phil@nwl.cc \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pablo@netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.