Diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Rename the release script to build-release.sh
Named like build-development.sh, so the two sort together in tools/.
Diffstat (limited to 'tools/build-release.sh')
| -rwxr-xr-x | tools/build-release.sh | 94 |
1 file changed, 94 insertions, 0 deletions
diff --git a/tools/build-release.sh b/tools/build-release.sh new file mode 100755 index 0000000..ade979c --- /dev/null +++ b/tools/build-release.sh @@ -0,0 +1,94 @@ +#!/bin/sh + +# Build cgit for a release with Linux hardening flags, which are ELF and GCC or +# Clang specific. The flags add a stack protector, fortified libc calls, a +# position independent executable, and full RELRO. By default Lua is pinned off +# so the binary needs no Lua at runtime, and running it as +# ./tools/build-release.sh lua links in the backend behind the "lua:" filter +# prefix instead, which needs a Lua dev package installed. + +set -eu + +if test "$#" -gt 1 +then + echo "usage: $0 [lua]" >&2 + exit 2 +fi +case "${1:-}" in +"") + set -- NO_LUA=1 + ;; +lua) + set -- + ;; +*) + echo "$0: unknown argument \"$1\", expected \"lua\" or nothing" >&2 + exit 2 + ;; +esac + +# Every make target below is written relative to the repository root. +cd "$(dirname "$0")/.." + +CC=${CC:-cc} + +# Not every hardening flag exists on every toolchain, and an unknown one would +# fail the build rather than be ignored, so the ones that might be missing are +# compiled before they are used. The argument is left unquoted so a caller can +# probe several flags at once. +supports() { + printf 'int main(void){return 0;}\n' >"$probe.c" + $CC $1 -o "$probe.out" "$probe.c" >/dev/null 2>&1 +} + +# The template is spelled out rather than passed with -t, whose handling of a +# prefix differs between the GNU and BSD versions. +probe=$(mktemp "${TMPDIR:-/tmp}/cgit-probe.XXXXXX") +trap 'rm -f "$probe" "$probe.c" "$probe.out"' EXIT + +CFLAGS="-O2 -g -Wall -fstack-protector-strong -fPIE -fno-plt" + +# Level 3 adds the bounds checks level 2 could not prove, and needs GCC 12 or +# Clang 15. Fall back rather than lose fortification altogether. +if supports "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -O2" +then + CFLAGS="$CFLAGS -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3" +else + CFLAGS="$CFLAGS -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2" +fi + +# Without this a large stack frame can step over a guard page rather than +# touch it. +if supports "-fstack-clash-protection" +then + CFLAGS="$CFLAGS -fstack-clash-protection" +fi + +# The debug info otherwise records the absolute build directory, so the same +# sources built in two checkouts would differ. +if supports "-ffile-prefix-map=/x=." +then + CFLAGS="$CFLAGS -ffile-prefix-map=$PWD=." +fi + +LDFLAGS="-pie -Wl,-z,relro,-z,now -Wl,-z,noexecstack" + +# These reach only the cgit objects, so git's own sources are not held to them. +# -Wformat-security is an error because a non-literal format with no arguments +# is never intentional. -Wformat-nonliteral would catch the module-link shape, +# a non-literal that does take arguments, but it also fires on va_list +# forwarding and on local format constants, so it is left to manual runs when +# touching anything that formats. +# +# make cgit CGIT_EXTRA_CFLAGS=-Wformat-nonliteral +# +CGIT_EXTRA_CFLAGS="-Wformat -Wformat-security -Werror=format-security" + +# The build starts from clean so the bundled git objects pick up the same +# flags, and cleanall rather than clean because only cleanall descends into +# vendor/git. CC goes on the command line because git's Makefile sets it, +# which would override the one from the environment the flags were probed +# with. +make cleanall +exec make "$@" CC="$CC" CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" \ + CGIT_EXTRA_CFLAGS="$CGIT_EXTRA_CFLAGS" |
