Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

restraint binaries are not built with relro/pie/bind_now #255

Open
comps opened this issue Jan 13, 2022 · 4 comments
Open

restraint binaries are not built with relro/pie/bind_now #255

comps opened this issue Jan 13, 2022 · 4 comments

Comments

@comps
Copy link

comps commented Jan 13, 2022

The annocheck(1) tool from the annobin-annocheck package reports that

# annocheck restraint-0.4.0-1.el9.x86_64.rpm restraint-client-0.4.0-1.el9.x86_64.rpm restraint-rhts-0.4.0-1.el9.x86_64.rpm
annocheck: Version 10.37.
Hardened: restraintd: FAIL: pie test because not built with '-Wl,-pie' (gcc/clang) or '-buildmode pie' (go)
Hardened: restraintd: FAIL: bind-now test because not linked with -Wl,-z,now
Hardened: restraintd: FAIL: cf-protection test because .note.gnu.property section did not contain the necessary flags
Hardened: Rerun annocheck with --verbose to see more information on the tests.
Hardened: restraintd: Overall: FAIL.
Hardened: rstrnt-abort: FAIL: pie test because not built with '-Wl,-pie' (gcc/clang) or '-buildmode pie' (go)
Hardened: rstrnt-abort: FAIL: bind-now test because not linked with -Wl,-z,now
Hardened: rstrnt-abort: FAIL: cf-protection test because .note.gnu.property section did not contain the necessary flags
Hardened: rstrnt-abort: Overall: FAIL.
Hardened: rstrnt-adjust-watchdog: FAIL: pie test because not built with '-Wl,-pie' (gcc/clang) or '-buildmode pie' (go)
Hardened: rstrnt-adjust-watchdog: FAIL: bind-now test because not linked with -Wl,-z,now
Hardened: rstrnt-adjust-watchdog: FAIL: cf-protection test because .note.gnu.property section did not contain the necessary flags
Hardened: rstrnt-adjust-watchdog: Overall: FAIL.
Hardened: rstrnt-report-log: FAIL: pie test because not built with '-Wl,-pie' (gcc/clang) or '-buildmode pie' (go)
Hardened: rstrnt-report-log: FAIL: bind-now test because not linked with -Wl,-z,now
Hardened: rstrnt-report-log: FAIL: cf-protection test because .note.gnu.property section did not contain the necessary flags
Hardened: rstrnt-report-log: Overall: FAIL.
Hardened: rstrnt-report-result: FAIL: pie test because not built with '-Wl,-pie' (gcc/clang) or '-buildmode pie' (go)
Hardened: rstrnt-report-result: FAIL: bind-now test because not linked with -Wl,-z,now
Hardened: rstrnt-report-result: FAIL: cf-protection test because .note.gnu.property section did not contain the necessary flags
Hardened: rstrnt-report-result: Overall: FAIL.
Hardened: rstrnt-sync: FAIL: pie test because not built with '-Wl,-pie' (gcc/clang) or '-buildmode pie' (go)
Hardened: rstrnt-sync: FAIL: bind-now test because not linked with -Wl,-z,now
Hardened: rstrnt-sync: Overall: FAIL.
Hardened: restraint: FAIL: pie test because not built with '-Wl,-pie' (gcc/clang) or '-buildmode pie' (go)
Hardened: restraint: FAIL: bind-now test because not linked with -Wl,-z,now
Hardened: restraint: FAIL: cf-protection test because .note.gnu.property section did not contain the necessary flags
Hardened: Rerun annocheck with --verbose to see more information on the tests.
Hardened: restraint: Overall: FAIL.

This may or may not be because the restraint.spec doesn't set LDFLAGS, it only sets CFLAGS:

%build
export CFLAGS="$RPM_OPT_FLAGS"
%if 0%{?rhel} == 5
%ifarch i386
# glib wants at least i486 for atomic instructions. RHEL6+ is already using i686.
export CFLAGS="$RPM_OPT_FLAGS -march=i486"
%endif
%endif
...

This should presumably export LDFLAGS:

export CFLAGS="$RPM_OPT_FLAGS"
export LDFLAGS="$RPM_LD_FLAGS"
...
@idorax
Copy link

idorax commented Jan 16, 2023

From the output of command annocheck,

Hardened: restraintd: FAIL: pie test because not built with '-Wl,-pie' (gcc/clang) or '-buildmode pie' (go)
Hardened: restraintd: FAIL: bind-now test because not linked with -Wl,-z,now
Hardened: restraintd: FAIL: cf-protection test because .note.gnu.property section did not contain the necessary flags
Hardened: restraintd: Overall: FAIL.
...<snip>...

Looks we should add -Wl,-pie to CFLAGS and add -Wl,-z,now to LDFLAGS when building the binaries as pie is Position-Independent-Executable for short.

@idorax
Copy link

idorax commented Jan 16, 2023

A manual test is done on x86_64 (Fedora 36). That is, annobin-annocheck can pass if we let CFLAGS inlude -Wl,-pie -fpie and LDFLAGS include -Wl,-z,now -pie.

01 - patch

diff --git a/src/Makefile b/src/Makefile
index e933843..a27d0bc 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -33,6 +33,19 @@ CFLAGS += -Wall -Werror -std=c99 $(shell pkg-config --cflags $(PACKAGES))
 # Keep this until we have Glib 2.68 in third-party module
 CFLAGS += -Wno-deprecated-declarations
 
+# XXX: Support to build binaries relro/pie/bind_now. For more,
+#      please refer to:
+#          https://github.com/restraint-harness/restraint/issues/255
+CFLAGS += -fshort-enums
+CFLAGS += -fcf-protection=full
+CFLAGS += -fplugin=annobin
+CFLAGS += -fstack-protector-strong
+CFLAGS += -D_FORTIFY_SOURCE=3
+CFLAGS += -D_GLIBCXX_ASSERTIONS
+CFLAGS += -Wl,-pie -fpie
+LDFLAGS += -Wl,-z,now
+LDFLAGS += -pie
+
 ifeq ($(STATIC), 1)
     # The LIBS list must start with static then followed with dynamic.
     # DYNAMICLIBS must be stripped out of THIRDPTYLIBS leaving

02 - build

Let's take a look at the building log after CFLAGS and LDFLAGS are updated,

$ make restraint
gcc -g -O2 -Wall -Werror -std=c99 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/gio-unix-2.0 -I/usr/include/json-c -I/usr/include/libsoup-2.4 -pthread -I/usr/include/libxml2  -Wno-deprecated-declarations -fshort-enums -fcf-protection=full -fplugin=annobin -fstack-protector-strong -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -Wl,-pie -fpie   -c -o client.o client.c
gcc -g -O2 -Wall -Werror -std=c99 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/gio-unix-2.0 -I/usr/include/json-c -I/usr/include/libsoup-2.4 -pthread -I/usr/include/libxml2  -Wno-deprecated-declarations -fshort-enums -fcf-protection=full -fplugin=annobin -fstack-protector-strong -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -Wl,-pie -fpie   -c -o errors.o errors.c
gcc -g -O2 -Wall -Werror -std=c99 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/gio-unix-2.0 -I/usr/include/json-c -I/usr/include/libsoup-2.4 -pthread -I/usr/include/libxml2  -Wno-deprecated-declarations -fshort-enums -fcf-protection=full -fplugin=annobin -fstack-protector-strong -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -Wl,-pie -fpie   -c -o xml.o xml.c
gcc -g -O2 -Wall -Werror -std=c99 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/gio-unix-2.0 -I/usr/include/json-c -I/usr/include/libsoup-2.4 -pthread -I/usr/include/libxml2  -Wno-deprecated-declarations -fshort-enums -fcf-protection=full -fplugin=annobin -fstack-protector-strong -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -Wl,-pie -fpie   -c -o utils.o utils.c
gcc -g -O2 -Wall -Werror -std=c99 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/gio-unix-2.0 -I/usr/include/json-c -I/usr/include/libsoup-2.4 -pthread -I/usr/include/libxml2  -Wno-deprecated-declarations -fshort-enums -fcf-protection=full -fplugin=annobin -fstack-protector-strong -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -Wl,-pie -fpie   -c -o process.o process.c
gcc -g -O2 -Wall -Werror -std=c99 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/gio-unix-2.0 -I/usr/include/json-c -I/usr/include/libsoup-2.4 -pthread -I/usr/include/libxml2  -Wno-deprecated-declarations -fshort-enums -fcf-protection=full -fplugin=annobin -fstack-protector-strong -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -Wl,-pie -fpie   -c -o restraint_forkpty.o restraint_forkpty.c
gcc -Wl,-z,now -pie -o restraint client.o errors.o xml.o utils.o process.o restraint_forkpty.o -ljson-c -larchive -lcurl -lsoup-2.4 -Wl,--export-dynamic -lgmodule-2.0 -pthread -lglib-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lxml2  -lutil -pthread

03 - check

Now we can check the restraint binaries via annobin-annocheck --verbose .... e.g.

$ annocheck --verbose restraint
annocheck: Version 10.93.
Hardened: restraint: info: no matching profile found.
Hardened: restraint: PASS: pie test 
Hardened: restraint: PASS: optimization test 
Hardened: restraint: PASS: pic test 
Hardened: restraint: PASS: stack-prot test 
Hardened: restraint: PASS: cf-protection test because correct flags found in .note.gnu.property note 
Hardened: restraint: PASS: writable-got test 
Hardened: restraint: PASS: dynamic-segment test 
Hardened: restraint: PASS: bind-now test 
Hardened: restraint: PASS: stack-clash test 
Hardened: restraint: PASS: fortify test because fortify note found 
Hardened: restraint: PASS: glibcxx-assertions test 
Hardened: restraint: PASS: entry test 
Hardened: restraint: PASS: gnu-stack test because stack segment exists with the correct permissions 
Hardened: restraint: PASS: gnu-relro test 
Hardened: restraint: PASS: gaps test because no gaps found in .text section coverage 
Hardened: restraint: PASS: notes test 
Hardened: restraint: skip: branch-protection test because not an AArch64 binary 
Hardened: restraint: skip: dynamic-tags test because AArch64 specific 
Hardened: restraint: PASS: fast test 
Hardened: restraint: skip: go-revision test because no GO compiled code found 
Hardened: restraint: PASS: instrumentation test 
Hardened: restraint: skip: only-go test because no GO compiled code found 
Hardened: restraint: PASS: production test 
Hardened: restraint: PASS: property-note test because CET enabled property note found 
Hardened: restraint: PASS: run-path test 
Hardened: restraint: PASS: rwx-seg test 
Hardened: restraint: PASS: short-enums test 
Hardened: restraint: skip: stack-realign test because not a 32-bit i686 executable 
Hardened: restraint: PASS: textrel test 
Hardened: restraint: PASS: threads test 
Hardened: restraint: PASS: unicode test 
Hardened: restraint: Overall: PASS.

@comps
Copy link
Author

comps commented Feb 7, 2023

Please do not try to reinvent the wheel if at all possible - Fedora/RHEL RPM build system already does this for you - you don't need an (incomplete?) explicit list of FLAGS.

Like I mentioned in my original post, reusing the variables already available to you as RPM_OPT_FLAGS (%{build_cflags}) and RPM_LD_FLAGS (%{build_ldflags}) should be all that's needed (this is what "normal" Fedora/RHEL packages are supposed to use).

export CFLAGS="$RPM_OPT_FLAGS"
export LDFLAGS="$RPM_LD_FLAGS"

(Or similar syntax with +=)

When a new hardening flag appears in gcc/clang and it gets added to redhat-rpm-config, you won't need to do anything and will simply inherit it.

@idorax
Copy link

idorax commented Feb 7, 2023

Hi @comps, thanks very much for your comment. Please help to review the PR #281, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants