diff mbox series

Add support for stack-protector

Message ID 20210110153900.19429-1-joel.peshkin@broadcom.com
State Changes Requested, archived
Delegated to: Tom Rini
Headers show
Series Add support for stack-protector | expand

Commit Message

Joel Peshkin Jan. 10, 2021, 3:39 p.m. UTC
Cc: Simon Glass <sjg@chromium.org>
Cc: Bin Meng <bmeng.cn@gmail.com>
Cc: Jagan Teki <jagan@amarulasolutions.com>
Cc: Kever Yang <kever.yang@rock-chips.com>
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Usama Arif <usama.arif@arm.com>
Cc: Sam Protsenko <joe.skb7@gmail.com>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Philippe Reynes <philippe.reynes@softathome.com>
Cc: Eugeniu Rosca <roscaeugeniu@gmail.com>
Cc: Jan Kiszka <jan.kiszka@siemens.com>

Signed-off-by: Joel Peshkin <joel.peshkin@broadcom.com>

---

 Makefile             |  4 ++++
 common/Kconfig       | 15 +++++++++++++++
 common/Makefile      |  2 ++
 common/stackprot.c   | 17 +++++++++++++++++
 scripts/Makefile.spl |  6 ++++++
 5 files changed, 44 insertions(+)
 create mode 100644 common/stackprot.c

Comments

Heinrich Schuchardt Jan. 10, 2021, 4:18 p.m. UTC | #1
On 1/10/21 4:39 PM, Joel Peshkin wrote:
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Bin Meng <bmeng.cn@gmail.com>
> Cc: Jagan Teki <jagan@amarulasolutions.com>
> Cc: Kever Yang <kever.yang@rock-chips.com>
> Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
> Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Cc: Usama Arif <usama.arif@arm.com>
> Cc: Sam Protsenko <joe.skb7@gmail.com>
> Cc: Masahiro Yamada <masahiroy@kernel.org>
> Cc: Philippe Reynes <philippe.reynes@softathome.com>
> Cc: Eugeniu Rosca <roscaeugeniu@gmail.com>
> Cc: Jan Kiszka <jan.kiszka@siemens.com>
>
> Signed-off-by: Joel Peshkin <joel.peshkin@broadcom.com>
>
> ---
>
>   Makefile             |  4 ++++
>   common/Kconfig       | 15 +++++++++++++++
>   common/Makefile      |  2 ++
>   common/stackprot.c   | 17 +++++++++++++++++
>   scripts/Makefile.spl |  6 ++++++
>   5 files changed, 44 insertions(+)
>   create mode 100644 common/stackprot.c
>
> diff --git a/Makefile b/Makefile
> index 3ee4cc00dd..6e7a81ec7d 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -677,7 +677,11 @@ else
>   KBUILD_CFLAGS	+= -O2
>   endif
>
> +ifeq ($(CONFIG_STACKPROTECTOR),y)
> +KBUILD_CFLAGS += $(call cc-option,-fstack-protector-strong)
> +else
>   KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector)
> +endif
>   KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks)
>
>   # disable stringop warnings in gcc 8+
> diff --git a/common/Kconfig b/common/Kconfig
> index 2bce8c9ba1..e30c3c4ab8 100644
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -595,6 +595,21 @@ config TPL_HASH
>   	  and the algorithms it supports are defined in common/hash.c. See
>   	  also CMD_HASH for command-line access.
>
> +config STACKPROTECTOR
> +	bool "Stack Protector buffer overflow detection"
> +	default n
> +	help
> +	  Enable stack smash detection through gcc built-in stack-protector
> +	  canary logic
> +
> +config SPL_STACKPROTECTOR
> +	bool "Stack Protector buffer overflow detection for SPL"
> +	default n
> +
> +config TPL_STACKPROTECTOR
> +	bool "Stack Protector buffer overflow detection for SPL"

%s/SPL/TPL/

> +	default n
> +
>   endmenu
>
>   menu "Update support"
> diff --git a/common/Makefile b/common/Makefile
> index bcf352d016..fe71e18317 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -138,3 +138,5 @@ obj-$(CONFIG_CMD_LOADB) += xyzModem.o
>   obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += xyzModem.o
>
>   obj-$(CONFIG_AVB_VERIFY) += avb_verify.o
> +obj-$(CONFIG_$(SPL_TPL_)STACKPROTECTOR) += stackprot.o
> +
> diff --git a/common/stackprot.c b/common/stackprot.c
> new file mode 100644
> index 0000000000..7c95b8544f
> --- /dev/null
> +++ b/common/stackprot.c
> @@ -0,0 +1,17 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + *  Copyright 2021 Broadcom
> + */
> +
> +#include <common.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +unsigned long __stack_chk_guard = 0xfeedf00ddeadbeef;
> +
> +void __stack_chk_fail(void)

The standalone EFI binaries are compiled with -fstack-protector-strong
when selecting CONFIG_STACKPROTECTOR.

Do we need a function __stack_chk_fail) in
lib/efi_selftest/efi_freestanding.c and
lib/efi_loader/efi_freestanding.c too?

Could you, please, provide unit tests demonstrating that the stack
protection is actually working SPL, main U-Boot, and the EFI binaries.

Best regards

Heinrich

> +{
> +	panic("Stack smashing detected in function: %p relocated from %p",
> +	      __builtin_return_address(0),
> +	      __builtin_return_address(0) - gd->reloc_off);
> +}
> diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
> index 9f1f7445d7..1505e4e851 100644
> --- a/scripts/Makefile.spl
> +++ b/scripts/Makefile.spl
> @@ -63,6 +63,12 @@ include $(srctree)/scripts/Makefile.lib
>   KBUILD_CFLAGS += -ffunction-sections -fdata-sections
>   LDFLAGS_FINAL += --gc-sections
>
> +ifeq ($(CONFIG_$(SPL_TPL_)STACKPROTECTOR),y)
> +KBUILD_CFLAGS += -fstack-protector-strong
> +else
> +KBUILD_CFLAGS += -fno-stack-protector
> +endif
> +
>   # FIX ME
>   cpp_flags := $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) $(UBOOTINCLUDE) \
>   							$(NOSTDINC_FLAGS)
>
Joel Peshkin Jan. 10, 2021, 7:44 p.m. UTC | #2
Hi Heinrich,

  Thank you for your comments.  I have 2 questions about how to proceed....

1) Unit test
  I can add a function that can be used to trigger an overrun, but I am not
sure where to include it as the stack protector prints the error message
and then resets uboot so it wouldn't fir in a unit test suite.

  I could add a CONFIG_STACKPROTECTOR_TEST_FAIL to add a
"test_stackprotector fail" command to the CLI and you could call the
underlying stackprot_test_fail() from code hacked into SPL and TPL

2) Standalone/EFI
    What we did for our own standalone code was to add the KBUILD_CFLAGS +=
-fno-stack-protector   to the Makefile for our specific standalone.   The
problem is there is no generic place from which all standalone/EFI is
called, so I could just leave this for maintainers of specific
standalone/EPI programs to add IF they are enabling STACKPROTECTOR (If they
don't enable it, they don't need to do anything) or I could add
KBUILD_CFLAGS += -fno-stack-protector  to  both lib/efi_setlftest/Makefile
and lib/efi_loader/Makefile

What would you suggest?

Regards,

Joel
Heinrich Schuchardt Jan. 10, 2021, 10:20 p.m. UTC | #3
Am 10. Januar 2021 20:44:15 MEZ schrieb Joel Peshkin <joel.peshkin@broadcom.com>:
>Hi Heinrich,
>
>Thank you for your comments.  I have 2 questions about how to
>proceed....
>
>1) Unit test
>I can add a function that can be used to trigger an overrun, but I am
>not
>sure where to include it as the stack protector prints the error
>message
>and then resets uboot so it wouldn't fir in a unit test suite.
>
>  I could add a CONFIG_STACKPROTECTOR_TEST_FAIL to add a
>"test_stackprotector fail" command to the CLI and you could call the
>underlying stackprot_test_fail() from code hacked into SPL and TPL

Additonally to the test command you will nedd a Python test (in /test/py/tests/) to excercise it.


>
>2) Standalone/EFI
>What we did for our own standalone code was to add the KBUILD_CFLAGS +=
>-fno-stack-protector   to the Makefile for our specific standalone.  
>The
>problem is there is no generic place from which all standalone/EFI is
>called, so I could just leave this for maintainers of specific
>standalone/EPI programs to add IF they are enabling STACKPROTECTOR (If
>they
>don't enable it, they don't need to do anything) or I could add
>KBUILD_CFLAGS += -fno-stack-protector  to  both

This would lead to contradictory arguments on the GCC command line.

>lib/efi_setlftest/Makefile
>and lib/efi_loader/Makefile

Have a look at CFLAGS_REMOVE in aforementioned Makefiles. 

Best regards

Heinrich

>
>What would you suggest?
>
>Regards,
>
>Joel
Nable Jan. 10, 2021, 10:40 p.m. UTC | #4
Hi,
> +
> +unsigned long __stack_chk_guard = 0xfeedf00ddeadbeef;

sizeof(unsigned long) isn't always 8, even gcc issues a warning when it's invoked with proper options (e.g. 32-bit build):

> warning: conversion from ‘long long unsigned int’ to ‘long unsigned int’ changes value from ‘18369602397475290863’ to ‘3735928559’ [-Woverflow]

Maybe there's some better way to initialize this variable. E.g. with #if … #else … #endif or using some initialization function that is invoked early.
I should also mention that a fixed canary value doesn't actually bring proper protection against exploits, thus run-time initialization with a random value is usually preferred.

I'm not sure whether it's important at all in bootloader code, I just wanted to be sure that it isn't unnoticed.

Cheers, Alex.
Joel Peshkin Jan. 11, 2021, 12:23 a.m. UTC | #5
Hi Alex,

   Yeah, I think I'll wind up with some ifdef code for the static init.
 In the case of arm (32-bit), there is actually a GCC bug that causes it to
use the address of the canary value instead of the canary value itself.
GCC upstream just fixed that a few days ago, but it may be a year or so
before the appropriate GCC version is widely available.

    I may eventually add an optional mechanism to allow the value to be
changed (very carefully) at runtime.  This has to be done early enough that
we cannot wait for an RNG to be identified via DTB, but there are a few
ways to keep arm and aarch64 from being too predictable and some boards may
have peripherals that can provide a sufficiently variable value.

-Joel




On Sun, Jan 10, 2021 at 2:40 PM Alex Sadovsky <
nable.maininbox@googlemail.com> wrote:

> Hi,
> > +
> > +unsigned long __stack_chk_guard = 0xfeedf00ddeadbeef;
>
> sizeof(unsigned long) isn't always 8, even gcc issues a warning when it's
> invoked with proper options (e.g. 32-bit build):
>
> > warning: conversion from ‘long long unsigned int’ to ‘long unsigned int’
> changes value from ‘18369602397475290863’ to ‘3735928559’ [-Woverflow]
>
> Maybe there's some better way to initialize this variable. E.g. with #if …
> #else … #endif or using some initialization function that is invoked early.
> I should also mention that a fixed canary value doesn't actually bring
> proper protection against exploits, thus run-time initialization with a
> random value is usually preferred.
>
> I'm not sure whether it's important at all in bootloader code, I just
> wanted to be sure that it isn't unnoticed.
>
> Cheers, Alex.
>
>
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index 3ee4cc00dd..6e7a81ec7d 100644
--- a/Makefile
+++ b/Makefile
@@ -677,7 +677,11 @@  else
 KBUILD_CFLAGS	+= -O2
 endif
 
+ifeq ($(CONFIG_STACKPROTECTOR),y)
+KBUILD_CFLAGS += $(call cc-option,-fstack-protector-strong)
+else
 KBUILD_CFLAGS += $(call cc-option,-fno-stack-protector)
+endif
 KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks)
 
 # disable stringop warnings in gcc 8+
diff --git a/common/Kconfig b/common/Kconfig
index 2bce8c9ba1..e30c3c4ab8 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -595,6 +595,21 @@  config TPL_HASH
 	  and the algorithms it supports are defined in common/hash.c. See
 	  also CMD_HASH for command-line access.
 
+config STACKPROTECTOR
+	bool "Stack Protector buffer overflow detection"
+	default n
+	help
+	  Enable stack smash detection through gcc built-in stack-protector
+	  canary logic
+
+config SPL_STACKPROTECTOR
+	bool "Stack Protector buffer overflow detection for SPL"
+	default n
+
+config TPL_STACKPROTECTOR
+	bool "Stack Protector buffer overflow detection for SPL"
+	default n
+
 endmenu
 
 menu "Update support"
diff --git a/common/Makefile b/common/Makefile
index bcf352d016..fe71e18317 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -138,3 +138,5 @@  obj-$(CONFIG_CMD_LOADB) += xyzModem.o
 obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += xyzModem.o
 
 obj-$(CONFIG_AVB_VERIFY) += avb_verify.o
+obj-$(CONFIG_$(SPL_TPL_)STACKPROTECTOR) += stackprot.o
+
diff --git a/common/stackprot.c b/common/stackprot.c
new file mode 100644
index 0000000000..7c95b8544f
--- /dev/null
+++ b/common/stackprot.c
@@ -0,0 +1,17 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  Copyright 2021 Broadcom
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+unsigned long __stack_chk_guard = 0xfeedf00ddeadbeef;
+
+void __stack_chk_fail(void)
+{
+	panic("Stack smashing detected in function: %p relocated from %p",
+	      __builtin_return_address(0),
+	      __builtin_return_address(0) - gd->reloc_off);
+}
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 9f1f7445d7..1505e4e851 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -63,6 +63,12 @@  include $(srctree)/scripts/Makefile.lib
 KBUILD_CFLAGS += -ffunction-sections -fdata-sections
 LDFLAGS_FINAL += --gc-sections
 
+ifeq ($(CONFIG_$(SPL_TPL_)STACKPROTECTOR),y)
+KBUILD_CFLAGS += -fstack-protector-strong
+else
+KBUILD_CFLAGS += -fno-stack-protector
+endif
+
 # FIX ME
 cpp_flags := $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) $(UBOOTINCLUDE) \
 							$(NOSTDINC_FLAGS)