1 /* Operating system specific code for generic dynamic loader functions.  Linux.
2    Copyright (C) 2000-2021 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <dl-sysdep.h>
20 #include <endian.h>
21 #include <fcntl.h>
22 #include <stdint.h>
23 #include <not-cancel.h>
24 
25 #ifndef MIN
26 # define MIN(a,b) (((a)<(b))?(a):(b))
27 #endif
28 
29 #define DL_SYSDEP_OSCHECK(FATAL)					      \
30   do {									      \
31     /* Test whether the kernel is new enough.  This test is only performed    \
32        if the library is not compiled to run on all kernels.  */	      \
33 									      \
34     int version = _dl_discover_osversion ();				      \
35     if (__glibc_likely (version >= 0))					      \
36       {									      \
37 	if (__builtin_expect (GLRO(dl_osversion) == 0, 1)		      \
38 	    || GLRO(dl_osversion) > version)				      \
39 	  GLRO(dl_osversion) = version;					      \
40 									      \
41 	/* Now we can test with the required version.  */		      \
42 	if (__LINUX_KERNEL_VERSION > 0 && version < __LINUX_KERNEL_VERSION)   \
43 	  /* Not sufficent.  */						      \
44 	  FATAL ("FATAL: kernel too old\n");				      \
45       }									      \
46     else if (__LINUX_KERNEL_VERSION > 0)				      \
47       FATAL ("FATAL: cannot determine kernel version\n");		      \
48   } while (0)
49 
50 static inline uintptr_t __attribute__ ((always_inline))
_dl_setup_stack_chk_guard(void * dl_random)51 _dl_setup_stack_chk_guard (void *dl_random)
52 {
53   union
54   {
55     uintptr_t num;
56     unsigned char bytes[sizeof (uintptr_t)];
57   } ret;
58 
59   /* We need in the moment only 8 bytes on 32-bit platforms and 16
60      bytes on 64-bit platforms.  Therefore we can use the data
61      directly and not use the kernel-provided data to seed a PRNG.  */
62   memcpy (ret.bytes, dl_random, sizeof (ret));
63 #if BYTE_ORDER == LITTLE_ENDIAN
64   ret.num &= ~(uintptr_t) 0xff;
65 #elif BYTE_ORDER == BIG_ENDIAN
66   ret.num &= ~((uintptr_t) 0xff << (8 * (sizeof (ret) - 1)));
67 #else
68 # error "BYTE_ORDER unknown"
69 #endif
70   return ret.num;
71 }
72 
73 static inline uintptr_t __attribute__ ((always_inline))
_dl_setup_pointer_guard(void * dl_random,uintptr_t stack_chk_guard)74 _dl_setup_pointer_guard (void *dl_random, uintptr_t stack_chk_guard)
75 {
76   uintptr_t ret;
77   memcpy (&ret, (char *) dl_random + sizeof (ret), sizeof (ret));
78   return ret;
79 }
80