Skip to content

.note.rustc dylib section flagged SHF_ALLOC on Linux (can cause crashes) #26764

Closed
@tylerwhall

Description

@tylerwhall

Having the metadata note section flagged "alloc" can cause two types of crashes in certain environments.

1. Dynamic loader crash

Glibc's dynamic loader will try to allocate and copy the entire section onto the stack which will crash if the stack size is limited. This section is particularly large (~2MB for libstd) - not something that can generally be expected to fit on the stack.

The loader is searching for .note.ABI-tag, but does so by reading in any PT_NOTE headers. Because the metadata section is flagged alloc, it gets an entry in the program header, causing it to get loaded by this code.
http://osxr.org/glibc/source/elf/dl-load.c?!v=glibc-2.19#1869 (Note the alloca() at 1879)

I think this may be the cause of #22528, or other crashes with open_verify() in the call stack.

A workaround of using objcopy -R to remove the section fixes this problem, but leaves the object in a brittle state, described below.

2. Crashes in stripped and prelinked shared objects

Working around 1. by stripping out .note.rustc causes a problem with section numbering. Pulling the section out from before another ALLOC section (.bss in the example below) causes that section to be renumbered. Neither GNU strip nor objcopy fix the rest of the references in the executable that point to the section by its index. In particular, entries in the .dynamic section now point to the next section (.comment, here) which breaks when prelinking.

Prelink decides not to fix up the symbols in the dynamic section because it thinks they point to .comment, a section that didn't get relocated during prelinking. So BSS gets relocated, but the dynamic symbols point to the non-prelinked address, causing the program to segfault when it tries to access exported symbols in BSS.

readelf -S libstd-4e7c5e5c.so (current behavior)

  [25] .data             PROGBITS        001938a0 18b8a0 0001a0 00  WA  0   0 16
  [26] .note.rustc       NOTE            00193a40 18ba40 2088d2 00  WA  0   0 16
  [27] .bss              NOBITS          0039c320 394312 000dc8 00  WA  0   0 16
  [28] .comment          PROGBITS        00000000 394312 000011 01  MS  0   0  1
  [29] .ARM.attributes   ARM_ATTRIBUTES  00000000 394323 00003d 00      0   0  1
  [30] .debug_aranges    PROGBITS        00000000 394360 0011a0 00      0   0  8

To fix this, I'm currently using this patch as a workaround.
tylerwhall@fc91059
It runs objcopy on the intermediate metadata object to remove the alloc and write flags. This causes the final link to place the metadata section at the end of the executable and not generate a program header entry.

The fixed version has the metadata with no flags set, no load address, and located near the end of the file along with the debug sections where it can be safely stripped.

readelf -S libstd-4e7c5e5c.so (desired behavior)

  [25] .data             PROGBITS        001938a0 18b8a0 0001a0 00  WA  0   0 16
  [26] .bss              NOBITS          00193a40 18ba40 000dc8 00  WA  0   0 16
  [27] .comment          PROGBITS        00000000 18ba40 000011 01  MS  0   0  1
  [28] .ARM.attributes   ARM_ATTRIBUTES  00000000 18ba51 00003d 00      0   0  1
  [29] .note.rustc       PROGBITS        00000000 18ba90 2088a7 00      0   0 16
  [30] .debug_aranges    PROGBITS        00000000 394338 0011a0 00      0   0  8

Obviously running objcopy like this is not portable. Calling llvm::LLVMSetGlobalConstant() on the metadata variable is enough to remove the SHF_WRITE flag, but I couldn't find a way with LLVM's API to output a section that didn't request to be loaded at run time. Hopefully someone who knows more about LLVM can come up with a more elegant solution to remove SHF_ALLOC from the intermediate metadata object.

Metadata

Metadata

Assignees

No one assigned

    Labels

    O-linuxOperating system: LinuxT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions