When building grub-2.06-r1 using clang and ld.lld with hardended flags, ld.lld fails to link with the error: ld.lld: error: can't create dynamic relocation R_X86_64_64 against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output CFLAGS and CXXFLAGS are set to: -march=native -O2 -pipe -fPIC -fstack-protector-strong -D_FORTIFY_SOURCE=2 LDFLAGS is set to: "-Wl,-O1 -Wl,--as-needed -fuse-ld=lld -rtlib=compiler-rt -unwindlib=libunwind -pie" Reproducible: Always Steps to Reproduce: 1. Emerge the clang toolchain as described at https://wiki.gentoo.org/wiki/Clang 2. Build GRUB with clang toolchain 3. Observe errror Actual Results: GRUB fails to build as ld.lld cannot create the required relocation records needed to link successfully. Expected Results: GRUB builds successfully.
Created attachment 758930 [details, diff] grub-2.06-clang-hardening.patch This patch modifies GRUB's configure script so --enable-stack-protector can be passed in unconditionally. If a GRUB platform does not support the flag, configure will now disable the option instead of aborting. This change allows the ebuild changes to work correctly.
Created attachment 758931 [details] grub-2.06-r1.ebuild Updated ebuild to enable GRUB's hardening settings. It introduces a new USE flag to control the setting. All versions of GCC that Gentoo supports also support stack-protector and are build with it implicitly enabled, so defaulting the flag to enabled should not cause any problems. This updated ebuild also contains the fix for bug 711072
Created attachment 758932 [details] grub.default-5 This file is not related to the stated issue. I am including it so the ebuild I provided can be used without modification. grub.default-5 fixes bug 711072
All the proposed fixes I added for GRUB can also be found at https://github.com/nvinson/magpie/tree/master/sys-boot/grub. I have used this repository to build test these changes.
Please provide a build log showing the failure.
Comment on attachment 758930 [details, diff] grub-2.06-clang-hardening.patch Please send this upstream.
I really don't like this approach. We should be able to resolve this without adding a mostly pointless USE flag.
I can reproduce the link failure with the following settings: CC=clang CFLAGS="-O2 -pipe -fPIC" LDFLAGS="-Wl,--as-needed -pie" The "-pie" in LDFLAGS is key. lld doesn't actually matter. The failure seems to happen when host utilities are linked against gnulib. Most of the objects are compiled using CFLAGS. However, CFLAGS don't seem to get used when compiling gnulib. Relevant output: > clang -DHAVE_CONFIG_H -I. -I/x/portage/sys-boot/grub-2.06-r1/work/grub-2.06/grub-core/lib/gnulib -I../../.. -D_FILE_OFFSET_BITS=64 -c -o argp-help.o /x/portage/sys-boot/grub-2.06-r1/work/grub-2.06/grub-core/lib/gnulib/argp-help.c > clang -std=gnu99 -O2 -pipe -fPIC -Wall -W -Wshadow -Wpointer-arith -Wundef -Wchar-subscripts -Wcomment -Wdeprecated-declarations -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Wformat-extra-args -Wformat-security -Wformat-y2k -Wimplicit -Wimplicit-function-declaration -Wimplicit-int -Wmain -Wmissing-braces -Wmissing-format-attribute -Wmultichar -Wparentheses -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -Wswitch -Wtrigraphs -Wunknown-pragmas -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wwrite-strings -Wnested-externs -Wstrict-prototypes -Wcast-align -Wextra -Wattributes -Wendif-labels -Winit-self -Wint-to-pointer-cast -Winvalid-pch -Wmissing-field-initializers -Wnonnull -Woverflow -Wvla -Wpointer-to-int-cast -Wstrict-aliasing -Wvariadic-macros -Wvolatile-register-var -Wpointer-sign -Wmissing-include-dirs -Wmissing-prototypes -Wmissing-declarations -Wformat=2 -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion -Wl,--as-needed -pie -o grub-mkimage util/grub_mkimage-grub-mkimage.o util/grub_mkimage-mkimage.o util/grub_mkimage-grub-mkimage32.o util/grub_mkimage-grub-mkimage64.o util/grub_mkimage-resolve.o grub-core/kern/emu/grub_mkimage-argp_common.o grub-core/osdep/grub_mkimage-init.o grub-core/osdep/grub_mkimage-config.o util/grub_mkimage-config.o libgrubmods.a libgrubgcry.a libgrubkern.a grub-core/lib/gnulib/libgnu.a -llzma -ldevmapper > /usr/bin/x86_64-pc-linux-gnu-ld: grub-core/lib/gnulib/libgnu.a(argp-help.o): relocation R_X86_64_32S against `.data' can not be used when making a PIE object; recompile with -fPIE Everything magically works with GCC because Gentoo configures GCC to emit PIE-compatible code by default.
(In reply to Mike Gilbert from comment #7) > I really don't like this approach. We should be able to resolve this without > adding a mostly pointless USE flag. The only alternative I could think to do is to check for '-pie' in LDFLAGS and check that the compiler is clang. However, if someone is trying to disable hardening when building GRUB, this approach would could mask that the attempt failed. That said, the ebuild would have to know how to compute the "effective" LDFLAGS so it doesn't get tripped up on things like "-pie -no-pie".
I see two possible solutions: 1. Fix the build system so that gnulib is built using CFLAGS. 2. Unconditionally remove "-pie" from LDFLAGS. This would result in a non-PIE build with clang, but that's better than a build failure.
This is complicated by the variable manipulation we do in src_configure. We copy CFLAGS/LDFLAGS into HOST_CFLAGS/HOST_LDFLAGS, and then unset CFLAGS and LDFLAGS. This is done to prevent CFLAGS/LDFLAGS from leaking into grub-core objects, which are very sensitive to various compiler options. Instead, we allow configure.ac to populate TARGET_CFLAGS and TARGET_LDFLAGS. Most of grub's build system uses HOST_CFLAGS and HOST_LDFLAGS or TARGET_CFLAGS and TARGET_LDFLAGS, but gnulib is an exception: it uses CFLAGS and LDFLAGS directly.
(In reply to Mike Gilbert from comment #10) > 2. Unconditionally remove "-pie" from LDFLAGS. This would result in a > non-PIE build with clang, but that's better than a build failure. That is what the proposed updated ebuild is doing now. It filters (via flag-o-matic's filter-flags command) -pie along with -fPIC, -fPIE, -fpic, -fpie, and -fstack-protector* before doing anything else in src_configure(). The point of filtering those flags is to reduce the likelihood of a bad GRUB build. The 'stack-protection' USE flag controls whether '--enable-stack-protection stack-protector=strong' is passed to GRUB's configure script or not. I default the USE flag to on because I think that it'll ensure the same hardening features are enabled when using both clang and gcc compilers. As an aside, I'm not set on the USE flag's name. I have no objection to changing its name if there is a preference to call it something else or to use an existing USE flag. When I did a (admittedly quick) USE flag scan, I didn't see any that felt like a good fit.
The bug has been closed via the following commit(s): https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=7c1b967ad02495722e66e18e2e6645388cf384e3 commit 7c1b967ad02495722e66e18e2e6645388cf384e3 Author: Mike Gilbert <floppym@gentoo.org> AuthorDate: 2021-12-15 04:54:32 +0000 Commit: Mike Gilbert <floppym@gentoo.org> CommitDate: 2021-12-15 04:56:54 +0000 sys-boot/grub: remove '-pie' from LDFLAGS Closes: https://bugs.gentoo.org/829165 Signed-off-by: Mike Gilbert <floppym@gentoo.org> sys-boot/grub/grub-2.06-r1.ebuild | 3 +++ sys-boot/grub/grub-9999.ebuild | 3 +++ 2 files changed, 6 insertions(+)