/* Operating system specific code for generic dynamic loader functions. Linux.
- Copyright (C) 2000,2001,2002,2004,2005 Free Software Foundation, Inc.
+ Copyright (C) 2000-2014 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
-#include <string.h>
-#include <fcntl.h>
-#include <sys/sysctl.h>
-#include <sys/utsname.h>
-#include "kernel-features.h"
+#include <kernel-features.h>
#include <dl-sysdep.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <not-cancel.h>
#ifndef MIN
# define MIN(a,b) (((a)<(b))?(a):(b))
#endif
-#ifdef SHARED
-/* This is the function used in the dynamic linker to print the fatal error
- message. */
-static inline void
-__attribute__ ((__noreturn__))
-dl_fatal (const char *str)
-{
- _dl_dprintf (2, str);
- _exit (1);
-}
-#endif
-
-static inline int __attribute__ ((always_inline))
-_dl_discover_osversion (void)
-{
- char bufmem[64];
- char *buf = bufmem;
- unsigned int version;
- int parts;
- char *cp;
- struct utsname uts;
-
- /* Try the uname system call. */
- if (__uname (&uts))
- {
- /* This was not successful. Now try reading the /proc filesystem. */
- int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY);
- if (fd < 0)
- return -1;
- ssize_t reslen = __read (fd, bufmem, sizeof (bufmem));
- __close (fd);
- if (reslen <= 0)
- /* This also didn't work. We give up since we cannot
- make sure the library can actually work. */
- return -1;
- buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0';
- }
- else
- buf = uts.release;
-
- /* Now convert it into a number. The string consists of at most
- three parts. */
- version = 0;
- parts = 0;
- cp = buf;
- while ((*cp >= '0') && (*cp <= '9'))
- {
- unsigned int here = *cp++ - '0';
-
- while ((*cp >= '0') && (*cp <= '9'))
- {
- here *= 10;
- here += *cp++ - '0';
- }
-
- ++parts;
- version <<= 8;
- version |= here;
-
- if (*cp++ != '.')
- /* Another part following? */
- break;
- }
-
- if (parts < 3)
- version <<= 8 * (3 - parts);
-
- return version;
-}
-
#define DL_SYSDEP_OSCHECK(FATAL) \
do { \
/* Test whether the kernel is new enough. This test is only performed \
int version = _dl_discover_osversion (); \
if (__builtin_expect (version >= 0, 1)) \
{ \
- GLRO(dl_osversion) = version; \
+ if (__builtin_expect (GLRO(dl_osversion) == 0, 1) \
+ || GLRO(dl_osversion) > version) \
+ GLRO(dl_osversion) = version; \
\
/* Now we can test with the required version. */ \
if (__LINUX_KERNEL_VERSION > 0 && version < __LINUX_KERNEL_VERSION) \
else if (__LINUX_KERNEL_VERSION > 0) \
FATAL ("FATAL: cannot determine kernel version\n"); \
} while (0)
+
+static inline uintptr_t __attribute__ ((always_inline))
+_dl_setup_stack_chk_guard (void *dl_random)
+{
+ union
+ {
+ uintptr_t num;
+ unsigned char bytes[sizeof (uintptr_t)];
+ } ret;
+
+#ifndef __ASSUME_AT_RANDOM
+ if (__builtin_expect (dl_random == NULL, 0))
+ {
+ const size_t filllen = sizeof (ret.bytes) - 1;
+ ret.num = 0;
+# ifdef ENABLE_STACKGUARD_RANDOMIZE
+ int fd = open_not_cancel_2 ("/dev/urandom", O_RDONLY);
+ if (fd >= 0)
+ {
+ ssize_t reslen = read_not_cancel (fd, ret.bytes + 1, filllen);
+ close_not_cancel_no_status (fd);
+ if (reslen == (ssize_t) filllen)
+ return ret.num;
+ }
+# endif
+ ret.bytes[filllen] = 255;
+ ret.bytes[filllen - 1] = '\n';
+ }
+ else
+#endif
+ {
+ /* We need in the moment only 8 bytes on 32-bit platforms and 16
+ bytes on 64-bit platforms. Therefore we can use the data
+ directly and not use the kernel-provided data to seed a PRNG. */
+ memcpy (ret.bytes, dl_random, sizeof (ret));
+#if BYTE_ORDER == LITTLE_ENDIAN
+ ret.num &= ~(uintptr_t) 0xff;
+#elif BYTE_ORDER == BIG_ENDIAN
+ ret.num &= ~((uintptr_t) 0xff << (8 * (sizeof (ret) - 1)));
+#else
+# error "BYTE_ORDER unknown"
+#endif
+ }
+ return ret.num;
+}
+
+static inline uintptr_t __attribute__ ((always_inline))
+_dl_setup_pointer_guard (void *dl_random, uintptr_t stack_chk_guard)
+{
+ uintptr_t ret;
+#ifndef __ASSUME_AT_RANDOM
+ if (dl_random == NULL)
+ {
+ ret = stack_chk_guard;
+# ifndef HP_TIMING_NONAVAIL
+ hp_timing_t now;
+ HP_TIMING_NOW (now);
+ ret ^= now;
+# endif
+ }
+ else
+#endif
+ memcpy (&ret, (char *) dl_random + sizeof (ret), sizeof (ret));
+ return ret;
+}