ldso: fix invalid early references to extern-linkage libc.page_size
authorRich Felker <dalias@aerifal.cx>
Wed, 30 Nov 2022 23:59:08 +0000 (18:59 -0500)
committerRich Felker <dalias@aerifal.cx>
Thu, 1 Dec 2022 00:07:34 +0000 (19:07 -0500)
commitf47a8cdd250d9163fcfb39bf4e9d813957c0b187
tree3df0e5326cf562ddb34024cc4270c31ff359617f
parent377218cb963aa20c6eb91781b0c79ad606631e6f
ldso: fix invalid early references to extern-linkage libc.page_size

when PAGE_SIZE is not constant, internal/libc.h defines it to expand
to libc.page_size. however, kernel_mapped_dso, reachable from stage 2
of the dynamic linker bootstrap (__dls2), needs PAGE_SIZE to interpret
the relro range. at this point the libc object is both uninitialized
and invalid to access according to our model for bootstrapping, which
does not assume any external-linkage objects are accessible until
stages 2b/3. in practice it likely worked because hidden visibility
tends to behave like internal linkage, but this is not a property that
the dynamic linker was designed to rely upon.

this bug likely manifested as relro malfunction on archs with variable
page size, due to incorrect mask when aligning the relro bounds to
page boundaries.

while there are certainly more direct ways to fix the known problem
point here, a maximally future-proof way is to just bypass the libc.h
PAGE_SIZE definition in the dynamic linker and instead have dynlink.c
define its own internal-linkage object for variable page size. then,
if anything else in stage 2 ever ends up referencing PAGE_SIZE, it
will just automatically work right.
ldso/dynlink.c