Просмотр исходного кода

Fix SSP support for riscv32

On modern 32-bit architectures like RISC-V (riscv32), legacy 32-bit
time syscalls like __NR_gettimeofday are intentionally omitted because
RV32 implements a strict time64-only ABI to avoid the Year 2038 bug.

Therefore, use AT_RANDOM from the auxiliary vector first, as glibc does,
to obtain random data for the stack canary. If AT_RANDOM is unavailable,
fall back to reading random data from /dev/urandom.

Tested with aarch64, riscv32 and riscv32 noMMU targets.

Co-developed-by: Charles Mirabile <cmirabil@redhat.com>
Waldemar Brodkorb 4 дней назад
Родитель
Сommit
6d8ec52b82

+ 0 - 10
extra/Configs/Config.in

@@ -2211,16 +2211,6 @@ config UCLIBC_HAS_SSP
 
 	  Most people will answer N.
 
-config SSP_QUICK_CANARY
-	bool "Use simple guard values without accessing /dev/urandom"
-	depends on UCLIBC_HAS_SSP
-	help
-	  Use gettimeofday(2) to define the __guard without accessing
-	  /dev/urandom.
-	  WARNING: This makes smashing stack protector vulnerable to timing
-	  	attacks.
-	  Most people will answer N.
-
 choice
 	prompt "Propolice protection blocking signal"
 	depends on UCLIBC_HAS_SSP

+ 0 - 12
ldso/include/dl-syscall.h

@@ -260,18 +260,6 @@ _dl_pread(int fd, void *buf, size_t count, off_t offset)
 }
 #endif
 
-#ifdef __UCLIBC_HAS_SSP__
-# include <sys/time.h>
-# define __NR__dl_gettimeofday __NR_gettimeofday
-static __always_inline _syscall2(int, _dl_gettimeofday, struct timeval *, tv,
-# ifdef __USE_BSD
-                        struct timezone *
-# else
-                        void *
-# endif
-						, tz)
-#endif
-
 /* Some architectures always use 12 as page shift for mmap2() eventhough the
  * real PAGE_SHIFT != 12.  Other architectures use the same value as
  * PAGE_SHIFT...

+ 3 - 1
ldso/ldso/ldso.c

@@ -1225,7 +1225,9 @@ of this helper program; chances are you did not intend to run this program.\n\
 #ifdef __UCLIBC_HAS_SSP__
 	_dl_debug_early("Setting up SSP guards\n");
 	/* Set up the stack checker's canary.  */
-	stack_chk_guard = _dl_setup_stack_chk_guard ();
+	stack_chk_guard = _dl_setup_stack_chk_guard (
+		_dl_auxvt[AT_RANDOM].a_type == AT_RANDOM ?
+		(void *)_dl_auxvt[AT_RANDOM].a_un.a_val : NULL);
 # ifdef THREAD_SET_STACK_GUARD
 	THREAD_SET_STACK_GUARD (stack_chk_guard);
 # else

+ 3 - 1
libc/misc/internals/__uClibc_main.c

@@ -296,7 +296,9 @@ void __uClibc_init(void)
 #ifndef SHARED
 # ifdef __UCLIBC_HAS_SSP__
     /* Set up the stack checker's canary.  */
-    stack_chk_guard = _dl_setup_stack_chk_guard();
+    stack_chk_guard = _dl_setup_stack_chk_guard(
+    _dl_auxvt[AT_RANDOM].a_type == AT_RANDOM ?
+        (void *)_dl_auxvt[AT_RANDOM].a_un.a_val : NULL);
 #  ifdef THREAD_SET_STACK_GUARD
     THREAD_SET_STACK_GUARD (stack_chk_guard);
 #  else

+ 35 - 23
libc/sysdeps/linux/common/dl-osinfo.h

@@ -21,43 +21,55 @@
 #  ifdef IS_IN_libc
 #   include <fcntl.h>
 #   include <unistd.h>
-#   include <sys/time.h>
+#   include <string.h>
 #   define OPEN open
 #   define READ read
 #   define CLOSE close
-#   define GETTIMEOFDAY gettimeofday
+#   define MEMCPY memcpy
 #  else
+#   include <dl-string.h>
 #   define OPEN _dl_open
 #   define READ _dl_read
 #   define CLOSE _dl_close
-#   define GETTIMEOFDAY _dl_gettimeofday
+#   define MEMCPY _dl_memcpy
 #  endif
 
-static __always_inline uintptr_t _dl_setup_stack_chk_guard(void)
+static __always_inline uintptr_t
+_dl_setup_stack_chk_guard(void *dl_random)
 {
-	uintptr_t ret;
-#  ifndef __SSP_QUICK_CANARY__
-	{
+	/* Fallback just the "terminator canary". */
+	uintptr_t ret = 0xFF0A0D00UL;
+
+	/*
+	 * Linux supplies random data through AT_RANDOM.
+	 * Use it directly when available.
+	 */
+	if (dl_random != NULL) {
+		MEMCPY(&ret, dl_random, sizeof(ret));
+	} else {
 		int fd = OPEN("/dev/urandom", O_RDONLY, 0);
-		if (fd >= 0) {
-			size_t size = READ(fd, &ret, sizeof(ret));
-			CLOSE(fd);
-			if (size == (size_t) sizeof(ret))
-				return ret;
-		}
+		if (fd < 0)
+			goto out;
+		uintptr_t tmp;
+		size_t size = READ(fd, &tmp, sizeof(tmp));
+		CLOSE(fd);
+		if (size != sizeof(tmp))
+			goto out;
+		ret = tmp;
 	}
-#  endif /* !__SSP_QUICK_CANARY__ */
+out:
 
-	/* Start with the "terminator canary". */
-	ret = 0xFF0A0D00UL;
+/* Make it harder to leak the canary by ensuring
+ * that the byte with the lowest address is a zero
+ * byte that will stop a rogue strcpy, printf %s, etc*/
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+	ret &= ~(uintptr_t)0xff;
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+	ret &= ~((uintptr_t)0xff << (8 * (sizeof(ret) - 1)));
+#else
+# error "Unknown byte order"
+#endif
 
-	/* Everything failed? Or we are using a weakened model of the
-	 * terminator canary */
-	{
-		struct timeval tv;
-		if (GETTIMEOFDAY(&tv, NULL) != (-1))
-			ret ^= tv.tv_usec ^ tv.tv_sec;
-	}
 	return ret;
 }
 # endif /* libc || rtld */