Re: [RFC PATCH v2 2/2] ELF: Add ELF program property parsing support

From: Dave Martin
Date: Fri Aug 30 2019 - 04:34:24 EST


On Fri, Aug 30, 2019 at 06:37:45AM +0100, Kees Cook wrote:
> On Fri, Aug 23, 2019 at 06:23:40PM +0100, Dave Martin wrote:
> > ELF program properties will needed for detecting whether to enable
> > optional architecture or ABI features for a new ELF process.
> >
> > For now, there are no generic properties that we care about, so do
> > nothing unless CONFIG_ARCH_USE_GNU_PROPERTY=y.
> >
> > Otherwise, the presence of properties using the PT_PROGRAM_PROPERTY
> > phdrs entry (if any), and notify each property to the arch code.
> >
> > For now, the added code is not used.
> >
> > Signed-off-by: Dave Martin <Dave.Martin@xxxxxxx>
>
> Reviewed-by: Kees Cook <keescook@xxxxxxxxxxxx>

Thanks for the review.

Do you have any thoughts on Yu-Cheng Yu's comments? It would be nice to
early-terminate the scan if we can, but my feeling so far was that the
scan is cheap, the number of properties is unlikely to be more than a
smallish integer, and the code separation benefits of just calling the
arch code for every property probably likely outweigh the costs of
having to iterate over every property. We could always optimise it
later if necessary.

I need to double-check that there's no way we can get stuck in an
infinite loop with the current code, though I've not seen it in my
testing. I should throw some malformed notes at it though.

> Note below...
>
> > [...]
> > +static int parse_elf_property(const char *data, size_t *off, size_t datasz,
> > + struct arch_elf_state *arch,
> > + bool have_prev_type, u32 *prev_type)
> > +{
> > + size_t size, step;
> > + const struct gnu_property *pr;
> > + int ret;
> > +
> > + if (*off == datasz)
> > + return -ENOENT;
> > +
> > + if (WARN_ON(*off > datasz || *off % elf_gnu_property_align))
> > + return -EIO;
> > +
> > + size = datasz - *off;
> > + if (size < sizeof(*pr))
> > + return -EIO;
> > +
> > + pr = (const struct gnu_property *)(data + *off);
> > + if (pr->pr_datasz > size - sizeof(*pr))
> > + return -EIO;
> > +
> > + step = round_up(sizeof(*pr) + pr->pr_datasz, elf_gnu_property_align);
> > + if (step > size)
> > + return -EIO;
> > +
> > + /* Properties are supposed to be unique and sorted on pr_type: */
> > + if (have_prev_type && pr->pr_type <= *prev_type)
> > + return -EIO;
> > + *prev_type = pr->pr_type;
> > +
> > + ret = arch_parse_elf_property(pr->pr_type,
> > + data + *off + sizeof(*pr),
> > + pr->pr_datasz, ELF_COMPAT, arch);
>
> I find it slightly hard to read the "cursor" motion in this parse. It
> feels strange, for example, to refer twice to "data + *off" with the
> second including consumed *pr size. Everything is fine AFAICT in the math,
> though, and I haven't been able to construct a convincingly "cleaner"
> version. Maybe:
>
> data += *off;
> pr = (const struct gnu_property *)data;
> data += sizeof(*pr);
> ...
> ret = arch_parse_elf_property(pr->pr_type, data,
> pr->pr_datasz, ELF_COMPAT, arch);

Fair point. The cursor is really *off, which I suppose I could update
as we go through this function, or cache in a local variable and assign
on the way out.

> But that feels disjoint from the "step" calculation, so... I think what
> you have is fine. :)

It's good to be as clear as possible about exactly how far we have
parsed, so I'll see if I can improve this when I repost.


Do you have any objection to merging patch 1 with this one? For
upstreaming purposes, it seems overkill for that to be a separate patch.

I may also convert elf_gnu_property_align to upper case, since unlike
the other related definitions this one isn't trying to look like a
struct tag.

Do you have any opinion on the WARN_ON()s? They should be un-hittable,
so they're documenting assumptions rather than protecting against
anything real. Maybe I should replace them with comments.

Cheers
---Dave