From patchwork Tue Aug 14 04:26:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Matt Weber X-Patchwork-Id: 957351 Return-Path: X-Original-To: incoming-buildroot@patchwork.ozlabs.org Delivered-To: patchwork-incoming-buildroot@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=busybox.net (client-ip=140.211.166.133; helo=hemlock.osuosl.org; envelope-from=buildroot-bounces@busybox.net; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=rockwellcollins.com Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41qKLY1yDhz9s7c for ; Tue, 14 Aug 2018 14:27:00 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 63A04857C1; Tue, 14 Aug 2018 04:26:56 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VBzYm4iiAkG9; Tue, 14 Aug 2018 04:26:53 +0000 (UTC) Received: from ash.osuosl.org (ash.osuosl.org [140.211.166.34]) by hemlock.osuosl.org (Postfix) with ESMTP id 217D5852D7; Tue, 14 Aug 2018 04:26:53 +0000 (UTC) X-Original-To: buildroot@lists.busybox.net Delivered-To: buildroot@osuosl.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by ash.osuosl.org (Postfix) with ESMTP id 3051B1CEF3C for ; Tue, 14 Aug 2018 04:26:49 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 2E10885155 for ; Tue, 14 Aug 2018 04:26:49 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 1QR2xhVWM1cJ for ; Tue, 14 Aug 2018 04:26:46 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from ch3vs01.rockwellcollins.com (ch3vs01.rockwellcollins.com [205.175.226.27]) by hemlock.osuosl.org (Postfix) with ESMTPS id 36BE4852D7 for ; Tue, 14 Aug 2018 04:26:46 +0000 (UTC) Received: from ofwch3n02.rockwellcollins.com (HELO ciulimr01.rockwellcollins.com) ([205.175.226.14]) by ch3vs01.rockwellcollins.com with ESMTP; 13 Aug 2018 23:26:44 -0500 X-Received: from largo.rockwellcollins.com (unknown [192.168.140.76]) by ciulimr01.rockwellcollins.com (Postfix) with ESMTP id C2B7E601DF; Mon, 13 Aug 2018 23:26:44 -0500 (CDT) From: Matt Weber To: buildroot@buildroot.org Date: Mon, 13 Aug 2018 23:26:41 -0500 Message-Id: <1534220803-26737-2-git-send-email-matthew.weber@rockwellcollins.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1534220803-26737-1-git-send-email-matthew.weber@rockwellcollins.com> References: <1534220803-26737-1-git-send-email-matthew.weber@rockwellcollins.com> MIME-Version: 1.0 Subject: [Buildroot] [RFC 1/3] toolchain/toolchain-wrapper: add linker wrapper X-BeenThere: buildroot@busybox.net X-Mailman-Version: 2.1.24 Precedence: list List-Id: Discussion and development of buildroot List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: buildroot-bounces@busybox.net Sender: "buildroot" - Updates symlink creation int/ext toolchain - Adds new source file for link wrapper with build/install Signed-off-by: Matthew Weber --- package/gcc/gcc.mk | 7 + .../toolchain-external/pkg-toolchain-external.mk | 3 + toolchain/toolchain-wrapper-ld.c | 252 +++++++++++++++++++++ toolchain/toolchain-wrapper.mk | 10 + 4 files changed, 272 insertions(+) create mode 100644 toolchain/toolchain-wrapper-ld.c diff --git a/package/gcc/gcc.mk b/package/gcc/gcc.mk index 1ae9b7e..a380004 100644 --- a/package/gcc/gcc.mk +++ b/package/gcc/gcc.mk @@ -334,6 +334,13 @@ define HOST_GCC_INSTALL_WRAPPER_AND_SIMPLE_SYMLINKS ln -sf toolchain-wrapper $(ARCH)-linux$${i##$(GNU_TARGET_NAME)}; \ ln -snf $$i.br_real $(ARCH)-linux$${i##$(GNU_TARGET_NAME)}.br_real; \ ;; \ + *ld) \ + rm -f $$i.br_real; \ + mv $$i $$i.br_real; \ + ln -sf toolchain-wrapper-ld $$i; \ + ln -sf toolchain-wrapper-ld $(ARCH)-linux$${i##$(GNU_TARGET_NAME)}; \ + ln -snf $$i.br_real $(ARCH)-linux$${i##$(GNU_TARGET_NAME)}.br_real; \ + ;; \ *) \ ln -snf $$i $(ARCH)-linux$${i##$(GNU_TARGET_NAME)}; \ ;; \ diff --git a/toolchain/toolchain-external/pkg-toolchain-external.mk b/toolchain/toolchain-external/pkg-toolchain-external.mk index 8b2c283..e4288bd 100644 --- a/toolchain/toolchain-external/pkg-toolchain-external.mk +++ b/toolchain/toolchain-external/pkg-toolchain-external.mk @@ -274,6 +274,9 @@ define TOOLCHAIN_EXTERNAL_INSTALL_WRAPPER ln -sf $$(echo $$i | sed 's%^$(HOST_DIR)%..%') .; \ fi \ ;; \ + *ld) \ + ln -sf toolchain-wrapper-ld $$base; \ + ;; \ *) \ ln -sf $$(echo $$i | sed 's%^$(HOST_DIR)%..%') .; \ ;; \ diff --git a/toolchain/toolchain-wrapper-ld.c b/toolchain/toolchain-wrapper-ld.c new file mode 100644 index 0000000..384c571 --- /dev/null +++ b/toolchain/toolchain-wrapper-ld.c @@ -0,0 +1,252 @@ +/** + * Buildroot wrapper for toolchains. This simply executes the real toolchain + * with a number of arguments hardcoded, to ensure the toolchain uses the + * correct configuration. + + * This file is based on the original wrapper code but updated for the linker. + * + * (C) 2011 Peter Korsgaard + * (C) 2011 Daniel Nyström + * (C) 2012 Arnout Vandecappelle (Essensium/Mind) + * (C) 2013 Spenser Gilliland + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +static char path[PATH_MAX]; + +/** + * GCC linker errors out with certain combinations of arguments (examples are + * static/shared/r/pie, so we have to ensure that we only pass the predefined + * one to the real compiler if the inverse option isn't in the argument list. + * This specifies the worst case number of extra arguments we might pass + * Currently, we may have: + * -pie + */ +#define EXCLUSIVE_ARGS 1 + + +/* A {string,length} tuple, to avoid computing strlen() on constants. + * - str must be a \0-terminated string + * - len does not account for the terminating '\0' + */ +struct str_len_s { + const char *str; + size_t len; +}; + +/* Define a {string,length} tuple. Takes an unquoted constant string as + * parameter. sizeof() on a string literal includes the terminating \0, + * but we don't want to count it. + */ +#define STR_LEN(s) { #s, sizeof(#s)-1 } + +/* List of paths considered unsafe for cross-compilation. + * + * An unsafe path is one that points to a directory with libraries or + * headers for the build machine, which are not suitable for the target. + */ +static const struct str_len_s unsafe_paths[] = { + STR_LEN(/lib), + STR_LEN(/usr/include), + STR_LEN(/usr/lib), + STR_LEN(/usr/local/include), + STR_LEN(/usr/local/lib), + { NULL, 0 }, +}; + +/* Unsafe options are options that specify a potentialy unsafe path, + * that will be checked by check_unsafe_path(), below. + */ +static const struct str_len_s unsafe_opts[] = { + STR_LEN(-I), + STR_LEN(-idirafter), + STR_LEN(-iquote), + STR_LEN(-isystem), + STR_LEN(-L), + { NULL, 0 }, +}; + +/* Check if path is unsafe for cross-compilation. Unsafe paths are those + * pointing to the standard native include or library paths. + * + * We print the arguments leading to the failure. For some options, gcc + * accepts the path to be concatenated to the argument (e.g. -I/foo/bar) + * or separated (e.g. -I /foo/bar). In the first case, we need only print + * the argument as it already contains the path (arg_has_path), while in + * the second case we need to print both (!arg_has_path). + * + * If paranoid, exit in error instead of just printing a warning. + */ +static void check_unsafe_path(const char *arg, + const char *path, + int paranoid, + int arg_has_path) +{ + const struct str_len_s *p; + + for (p=unsafe_paths; p->str; p++) { + if (strncmp(path, p->str, p->len)) + continue; + fprintf(stderr, + "%s: %s: unsafe header/library path used in cross-compilation: '%s%s%s'\n", + program_invocation_short_name, + paranoid ? "ERROR" : "WARNING", + arg, + arg_has_path ? "" : "' '", /* close single-quote, space, open single-quote */ + arg_has_path ? "" : path); /* so that arg and path are properly quoted. */ + if (paranoid) + exit(1); + } +} + +int main(int argc, char **argv) +{ + char **args, **cur, **exec_args; + char *relbasedir, *absbasedir; + char *progpath = argv[0]; + char *basename; + char *env_debug; + char *paranoid_wrapper; + int paranoid; + int ret, i, count = 0, debug; + + /* Calculate the relative paths */ + basename = strrchr(progpath, '/'); + if (basename) { + *basename = '\0'; + basename++; + relbasedir = malloc(strlen(progpath) + 7); + if (relbasedir == NULL) { + perror(__FILE__ ": malloc"); + return 2; + } + sprintf(relbasedir, "%s/..", argv[0]); + absbasedir = realpath(relbasedir, NULL); + } else { + basename = progpath; + absbasedir = malloc(PATH_MAX + 1); + ret = readlink("/proc/self/exe", absbasedir, PATH_MAX); + if (ret < 0) { + perror(__FILE__ ": readlink"); + return 2; + } + absbasedir[ret] = '\0'; + for (i = ret; i > 0; i--) { + if (absbasedir[i] == '/') { + absbasedir[i] = '\0'; + if (++count == 2) + break; + } + } + } + if (absbasedir == NULL) { + perror(__FILE__ ": realpath"); + return 2; + } + + /* Fill in the relative paths */ +#ifdef BR_CROSS_PATH_REL + ret = snprintf(path, sizeof(path), "%s/" BR_CROSS_PATH_REL "/%s" BR_CROSS_PATH_SUFFIX, absbasedir, basename); +#elif defined(BR_CROSS_PATH_ABS) + ret = snprintf(path, sizeof(path), BR_CROSS_PATH_ABS "/%s" BR_CROSS_PATH_SUFFIX, basename); +#else + ret = snprintf(path, sizeof(path), "%s/bin/%s" BR_CROSS_PATH_SUFFIX, absbasedir, basename); +#endif + if (ret >= sizeof(path)) { + perror(__FILE__ ": overflow"); + return 3; + } + + cur = args = malloc((sizeof(char *) * (argc + EXCLUSIVE_ARGS))); + if (args == NULL) { + perror(__FILE__ ": malloc"); + return 2; + } + +#ifdef BR2_RELRO_FULL + /* pie isn't compatible with static and shared/r accomplish the same thing */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-static") || + !strcmp(argv[i], "-shared") || + !strcmp(argv[i], "-r")) + break; + } + + if (i == argc) + *cur++ = "-pie"; +#endif + + paranoid_wrapper = getenv("BR_COMPILER_PARANOID_UNSAFE_PATH"); + if (paranoid_wrapper && strlen(paranoid_wrapper) > 0) + paranoid = 1; + else + paranoid = 0; + + /* Check for unsafe library and header paths */ + for (i = 1; i < argc; i++) { + const struct str_len_s *opt; + for (opt=unsafe_opts; opt->str; opt++ ) { + /* Skip any non-unsafe option. */ + if (strncmp(argv[i], opt->str, opt->len)) + continue; + + /* Handle both cases: + * - path is a separate argument, + * - path is concatenated with option. + */ + if (argv[i][opt->len] == '\0') { + i++; + if (i == argc) + break; + check_unsafe_path(argv[i-1], argv[i], paranoid, 0); + } else + check_unsafe_path(argv[i], argv[i] + opt->len, paranoid, 1); + } + } + + /* append forward args */ + memcpy(cur, &argv[1], sizeof(char *) * (argc - 1)); + cur += argc - 1; + + /* finish with NULL termination */ + *cur = NULL; + + exec_args = args; + + /* Debug the wrapper to see actual arguments passed to + * the compiler: + * unset, empty, or 0: do not trace + * set to 1 : trace all arguments on a single line + * set to 2 : trace one argument per line + */ + if ((env_debug = getenv("BR2_DEBUG_WRAPPER"))) { + debug = atoi(env_debug); + if (debug > 0) { + fprintf(stderr, "Toolchain wrapper executing:"); + for (i = 0; exec_args[i]; i++) + fprintf(stderr, "%s'%s'", + (debug == 2) ? "\n " : " ", exec_args[i]); + fprintf(stderr, "\n"); + } + } + + if (execv(exec_args[0], exec_args)) + perror(path); + + free(args); + + return 2; +} diff --git a/toolchain/toolchain-wrapper.mk b/toolchain/toolchain-wrapper.mk index b8074ef..19cd45d 100644 --- a/toolchain/toolchain-wrapper.mk +++ b/toolchain/toolchain-wrapper.mk @@ -45,14 +45,24 @@ ifeq ($(BR2_CCACHE_USE_BASEDIR),y) TOOLCHAIN_WRAPPER_ARGS += -DBR_CCACHE_BASEDIR='"$(BASE_DIR)"' endif +ifeq ($(BR2_RELRO_FULL),y) +TOOLCHAIN_WRAPPER_ARGS += -DBR2_RELRO_FULL +endif + define TOOLCHAIN_WRAPPER_BUILD $(HOSTCC) $(HOST_CFLAGS) $(TOOLCHAIN_WRAPPER_ARGS) \ -s -Wl,--hash-style=$(TOOLCHAIN_WRAPPER_HASH_STYLE) \ toolchain/toolchain-wrapper.c \ -o $(@D)/toolchain-wrapper + $(HOSTCC) $(HOST_CFLAGS) $(TOOLCHAIN_WRAPPER_ARGS) \ + -s -Wl,--hash-style=$(TOOLCHAIN_WRAPPER_HASH_STYLE) \ + toolchain/toolchain-wrapper-ld.c \ + -o $(@D)/toolchain-wrapper-ld endef define TOOLCHAIN_WRAPPER_INSTALL $(INSTALL) -D -m 0755 $(@D)/toolchain-wrapper \ $(HOST_DIR)/bin/toolchain-wrapper + $(INSTALL) -D -m 0755 $(@D)/toolchain-wrapper-ld \ + $(HOST_DIR)/bin/toolchain-wrapper-ld endef