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

Re: RFC: Audit external function called indirectly via GOT



>> My suggestion was that the GOT entry could be statically initialized
>> by the linker to point to the provisional PLT entry, rather than
>> forcing the dynamic loader to go through all this messy computation.
>> If auditing is not enabled, it would process the GLOB_DAT relocation
>> normally, and set the GOT entry to point to the actual function,
>
> elf_machine_plt_address in my glibc patch:
>
> https://github.com/hjl-tools/glibc/commit/aa8f2f5b9f395769f30d776649a11c2a045dd9e2
>
> has
>
> if (__glibc_unlikely (GLRO(dl_naudit) > 0)
> && map->l_info[ADDRIDX (DT_GNU_PLT)]
> && map->l_info[DT_JMPREL]
> && ELFW(ST_TYPE) (refsym->st_info) == STT_FUNC)
> {
>    Find the matching JUMP_SLOT relocation.
> }
> else
>    Use the original resolution.
>
> If LD_AUDIT is unused, the whole thing is skipped.
>
>> bypassing the provisional PLT and PLTGOT entries completely. If
>> auditing is enabled, it could simply ignore the GLOB_DAT relocation
>> (or, if the binary is PIE, it could process it as a RELATIVE
>> relocation), and the -fno-plt calls will end up jumping to the
>> provisional PLT entry.
>>
>> (This is already how we handle the PLTGOT entries: the linker
>> statically initializes the entries to point to part (b)* of the PLT
>> entry, while putting JUMP_SLOT relocations for those entries into the
>> JMPREL table.)
>>
>> I think if you do that, none of these extra dynamic table entries will
>> be needed, except for the IGNORE_JMPREL flag that indicates there are
>> no JMPREL slots other than those for the provisional PLT entries. How
>> useful is that flag? If the final program has even one external call
>> that was *not* compiled with -fno-plt, you won't be able to set it.
>> Would it be better to partition the JMPREL and PLT tables into
>> "regular" and "provisional" entries? That would take just a single new
>> DT_PROVISIONAL_JMPREL entry to tell the dynamic loader where the
>> JMPREL entries for the provisional PLT entries begin; it can ignore
>> everything past that point when auditing is turned off.
>
> These new dynamic tags are used to compute PLT offset from GOT offset.
> See elf_machine_plt_address in my patch.

Kinda reminds me of "These go to 11."

What I'm suggesting eliminates the need for the dynamic loader to
compute the PLT offset from the GOT offset, and therefore eliminates
the need for all these additional DT entries.

>> I suppose you may also want to partition the GLOB_DAT relocations, so
>> that the dynamic loader can easily figure out which ones to ignore
>> when auditing is enabled. That would take another dynamic table entry.
>>
>> Now, why do we need both the regular GOT entry and the provisional
>> PLTGOT entry? If the program is linked with -z relro and lazy binding,
>> you can put the GOT entries in the RELRO segment, and the PLTGOT
>> entries in writable data. That gives you the security when auditing is
>> turned off, and the ability to dynamically patch the PLTGOT when it's
>> turned on. In any other case, however, I see no reason to have both.
>> If you get rid of the GOT entry, and have the point of call jump
>> indirectly through the PLTGOT entry, which is initialized to point to
>> part (b) of the PLT entry, everything should work the same as without
>> -fno-plt. Essentially, all -fno-plt would do is inline part (a) of the
>> PLT entry.
>
> I want to use both so that GOT is read-only after relocation in
> normal case and the writable PLTGOT is only used for LD_AUDIT.

But if the program isn't linked with relro, the PLTGOT entries remain
writable and you have no need for both. If it's linked with immediate
binding and relro, the PLTGOT entries become relro, and again you have
no need for both. The only case where you can make an argument for
both is when the program is linked with both relro and lazy binding.
But I don't see why you need the additional security if you're not
bothering to link with immediate binding.

-cary