1 /* Machine-dependent program header inspection for the ELF loader.
2    Copyright (C) 2014-2022 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 #ifndef _DL_MACHINE_REJECT_PHDR_H
20 #define _DL_MACHINE_REJECT_PHDR_H 1
21 
22 #include <unistd.h>
23 #include <sys/prctl.h>
24 
25 #if defined PR_GET_FP_MODE && defined PR_SET_FP_MODE
26 # define HAVE_PRCTL_FP_MODE 1
27 #else
28 # define HAVE_PRCTL_FP_MODE 0
29 #endif
30 
31 /* Reject an object with a debug message.  */
32 #define REJECT(str, args...)						      \
33   {									      \
34     if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))		      \
35       _dl_debug_printf (str, ##args);					      \
36     return true;							      \
37   }
38 
39 /* Search the program headers for the ABI Flags.  */
40 
ElfW(Phdr)41 static inline const ElfW(Phdr) *
42 find_mips_abiflags (const ElfW(Phdr) *phdr, ElfW(Half) phnum)
43 {
44   const ElfW(Phdr) *ph;
45 
46   for (ph = phdr; ph < &phdr[phnum]; ++ph)
47     if (ph->p_type == PT_MIPS_ABIFLAGS)
48       return ph;
49   return NULL;
50 }
51 
52 /* Cache the FP ABI value from the PT_MIPS_ABIFLAGS program header.  */
53 
54 static bool
cached_fpabi_reject_phdr_p(struct link_map * l)55 cached_fpabi_reject_phdr_p (struct link_map *l)
56 {
57   if (l->l_mach.fpabi == 0)
58     {
59       const ElfW(Phdr) *ph = find_mips_abiflags (l->l_phdr, l->l_phnum);
60 
61       if (ph)
62 	{
63 	  Elf_MIPS_ABIFlags_v0 * mips_abiflags;
64 	  if (ph->p_filesz < sizeof (Elf_MIPS_ABIFlags_v0))
65 	    REJECT ("   %s: malformed PT_MIPS_ABIFLAGS found\n", l->l_name);
66 
67 	  mips_abiflags = (Elf_MIPS_ABIFlags_v0 *) (l->l_addr + ph->p_vaddr);
68 
69 	  if (__glibc_unlikely (mips_abiflags->flags2 != 0))
70 	    REJECT ("   %s: unknown MIPS.abiflags flags2: %u\n", l->l_name,
71 		    mips_abiflags->flags2);
72 
73 	  l->l_mach.fpabi = mips_abiflags->fp_abi;
74 	  l->l_mach.odd_spreg = (mips_abiflags->flags1
75 				 & MIPS_AFL_FLAGS1_ODDSPREG) != 0;
76 	}
77       else
78 	{
79 	  l->l_mach.fpabi = -1;
80 	  l->l_mach.odd_spreg = true;
81 	}
82     }
83   return false;
84 }
85 
86 /* Return a description of the specified floating-point ABI.  */
87 
88 static const char *
fpabi_string(int fpabi)89 fpabi_string (int fpabi)
90 {
91   switch (fpabi)
92     {
93     case Val_GNU_MIPS_ABI_FP_ANY:
94       return "Hard or soft float";
95     case Val_GNU_MIPS_ABI_FP_DOUBLE:
96       return "Hard float (double precision)";
97     case Val_GNU_MIPS_ABI_FP_SINGLE:
98       return "Hard float (single precision)";
99     case Val_GNU_MIPS_ABI_FP_SOFT:
100       return "Soft float";
101     case Val_GNU_MIPS_ABI_FP_OLD_64:
102       return "Unsupported FP64";
103     case Val_GNU_MIPS_ABI_FP_XX:
104       return "Hard float (32-bit CPU, Any FPU)";
105     case Val_GNU_MIPS_ABI_FP_64:
106       return "Hard float (32-bit CPU, 64-bit FPU)";
107     case Val_GNU_MIPS_ABI_FP_64A:
108       return "Hard float compat (32-bit CPU, 64-bit FPU)";
109     case -1:
110       return "Double precision, single precision or soft float";
111     default:
112       return "Unknown FP ABI";
113     }
114 }
115 
116 /* A structure to describe the requirements of each FP ABI extension.
117    Each field says whether the ABI can be executed in that mode.  The FR0 field
118    is actually overloaded and means 'default' FR mode for the ABI.  I.e. For
119    O32 it is FR0 and for N32/N64 it is actually FR1.  Since this logic is
120    focussed on the intricacies of mode management for O32 we call the field
121    FR0.  */
122 
123 struct abi_req
124 {
125   bool single;
126   bool soft;
127   bool fr0;
128   bool fr1;
129   bool fre;
130 };
131 
132 /* FP ABI requirements for all Val_GNU_MIPS_ABI_FP_* values.  */
133 
134 static const struct abi_req reqs[Val_GNU_MIPS_ABI_FP_MAX + 1] =
135     {{true,  true,  true,  true,  true},  /* Any */
136      {false, false, true,  false, true},  /* Double-float */
137      {true,  false, false, false, false}, /* Single-float */
138      {false, true,  false, false, false}, /* Soft-float */
139      {false, false, false, false, false}, /* old-FP64 */
140      {false, false, true,  true,  true},  /* FPXX */
141      {false, false, false, true,  false}, /* FP64 */
142      {false, false, false, true,  true}}; /* FP64A */
143 
144 /* FP ABI requirements for objects without a PT_MIPS_ABIFLAGS segment.  */
145 
146 static const struct abi_req none_req = { true, true, true, false, true };
147 
148 /* Return true iff ELF program headers are incompatible with the running
149    host.  This verifies that floating-point ABIs are compatible and
150    re-configures the hardware mode if necessary.  This code handles both the
151    DT_NEEDED libraries and the dlopen'ed libraries.  It also accounts for the
152    impact of dlclose.  */
153 
154 static bool __attribute_used__
elf_machine_reject_phdr_p(const ElfW (Phdr)* phdr,unsigned int phnum,const char * buf,size_t len,struct link_map * map,int fd)155 elf_machine_reject_phdr_p (const ElfW(Phdr) *phdr, unsigned int phnum,
156 			   const char *buf, size_t len, struct link_map *map,
157 			   int fd)
158 {
159   const ElfW(Phdr) *ph = find_mips_abiflags (phdr, phnum);
160   struct link_map *l;
161   Lmid_t nsid;
162   int in_abi = -1;
163   struct abi_req in_req;
164   Elf_MIPS_ABIFlags_v0 *mips_abiflags = NULL;
165   bool perfect_match = false;
166 #if _MIPS_SIM == _ABIO32
167   unsigned int cur_mode = -1;
168 # if HAVE_PRCTL_FP_MODE
169   bool cannot_mode_switch = false;
170 
171   /* Get the current hardware mode.  */
172   cur_mode = __prctl (PR_GET_FP_MODE);
173 # endif
174 #endif
175 
176   /* Read the attributes section.  */
177   if (ph != NULL)
178     {
179       ElfW(Addr) size = ph->p_filesz;
180 
181       if (ph->p_offset + size <= len)
182 	mips_abiflags = (Elf_MIPS_ABIFlags_v0 *) (buf + ph->p_offset);
183       else
184 	{
185 	  mips_abiflags = alloca (size);
186 	  __lseek (fd, ph->p_offset, SEEK_SET);
187 	  if (__libc_read (fd, (void *) mips_abiflags, size) != size)
188 	    REJECT ("   unable to read PT_MIPS_ABIFLAGS\n");
189 	}
190 
191       if (size < sizeof (Elf_MIPS_ABIFlags_v0))
192 	REJECT ("   contains malformed PT_MIPS_ABIFLAGS\n");
193 
194       if (__glibc_unlikely (mips_abiflags->flags2 != 0))
195 	REJECT ("   unknown MIPS.abiflags flags2: %u\n", mips_abiflags->flags2);
196 
197       in_abi = mips_abiflags->fp_abi;
198     }
199 
200   /* ANY is compatible with anything.  */
201   perfect_match |= (in_abi == Val_GNU_MIPS_ABI_FP_ANY);
202 
203   /* Unknown ABIs are rejected.  */
204   if (in_abi != -1 && in_abi > Val_GNU_MIPS_ABI_FP_MAX)
205     REJECT ("   uses unknown FP ABI: %u\n", in_abi);
206 
207   /* Obtain the initial requirements.  */
208   in_req = (in_abi == -1) ? none_req : reqs[in_abi];
209 
210   /* Check that the new requirement does not conflict with any currently
211      loaded object.  */
212   for (nsid = 0; nsid < DL_NNS; ++nsid)
213     for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
214       {
215 	struct abi_req existing_req;
216 
217 	if (cached_fpabi_reject_phdr_p (l))
218 	  return true;
219 
220 #if _MIPS_SIM == _ABIO32
221 	/* A special case arises for O32 FP64 and FP64A where the kernel
222 	   pre-dates PT_MIPS_ABIFLAGS.  These ABIs will be blindly loaded even
223 	   if the hardware mode is unavailable or disabled.  In this
224 	   circumstance the prctl call to obtain the current mode will fail.
225 	   Detect this situation here and reject everything.  This will
226 	   effectively prevent dynamically linked applications from failing in
227 	   unusual ways but there is nothing we can do to help static
228 	   applications.  */
229 	if ((l->l_mach.fpabi == Val_GNU_MIPS_ABI_FP_64A
230 	     || l->l_mach.fpabi == Val_GNU_MIPS_ABI_FP_64)
231 	    && cur_mode == -1)
232 	  REJECT ("   found %s running in the wrong mode\n",
233 		  fpabi_string (l->l_mach.fpabi));
234 #endif
235 
236 	/* Found a perfect match, success.  */
237 	perfect_match |= (in_abi == l->l_mach.fpabi);
238 
239 	/* Unknown ABIs are rejected.  */
240 	if (l->l_mach.fpabi != -1 && l->l_mach.fpabi > Val_GNU_MIPS_ABI_FP_MAX)
241 	  REJECT ("   found unknown FP ABI: %u\n", l->l_mach.fpabi);
242 
243 	existing_req = (l->l_mach.fpabi == -1 ? none_req
244 			: reqs[l->l_mach.fpabi]);
245 
246 	/* Merge requirements.  */
247 	in_req.soft &= existing_req.soft;
248 	in_req.single &= existing_req.single;
249 	in_req.fr0 &= existing_req.fr0;
250 	in_req.fr1 &= existing_req.fr1;
251 	in_req.fre &= existing_req.fre;
252 
253 	/* If there is at least one mode which is still usable then the new
254 	   object can be loaded.  */
255 	if (in_req.single || in_req.soft || in_req.fr1 || in_req.fr0
256 	    || in_req.fre)
257 	  {
258 #if _MIPS_SIM == _ABIO32 && HAVE_PRCTL_FP_MODE
259 	    /* Account for loaded ABIs which prohibit mode switching.  */
260 	    if (l->l_mach.fpabi == Val_GNU_MIPS_ABI_FP_XX)
261 	      cannot_mode_switch |= l->l_mach.odd_spreg;
262 #endif
263 	  }
264 	else
265 	  REJECT ("   uses %s, already loaded %s\n",
266 		  fpabi_string (in_abi),
267 		  fpabi_string (l->l_mach.fpabi));
268       }
269 
270 #if _MIPS_SIM == _ABIO32
271   /* At this point we know that the newly loaded object is compatible with all
272      existing objects but the hardware mode may not be correct.  */
273   if ((in_req.fr1 || in_req.fre || in_req.fr0)
274       && !perfect_match)
275     {
276       if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
277 	_dl_debug_printf ("   needs %s%s mode\n", in_req.fr0 ? "FR0 or " : "",
278 			  (in_req.fre && !in_req.fr1) ? "FRE" : "FR1");
279 
280       /* If the PR_GET_FP_MODE is not supported then only FR0 is available.
281 	 If the overall requirements cannot be met by FR0 then reject the
282 	 object.  */
283       if (cur_mode == -1)
284 	return !in_req.fr0;
285 
286 # if HAVE_PRCTL_FP_MODE
287       {
288 	unsigned int fr1_mode = PR_FP_MODE_FR;
289 
290 	/* It is not possible to change the mode of a thread which may be
291 	   executing FPXX code with odd-singles.  If an FPXX object with
292 	   odd-singles is loaded then just check the current mode is OK. This
293 	   can be either the FR1 mode or FR0 if the requirements are met by
294 	   FR0.  */
295 	if (cannot_mode_switch)
296 	  return (!(in_req.fre && cur_mode == (PR_FP_MODE_FR | PR_FP_MODE_FRE))
297 		  && !(in_req.fr1 && cur_mode == PR_FP_MODE_FR)
298 		  && !(in_req.fr0 && cur_mode == 0));
299 
300 	/* If the overall requirements can be satisfied by FRE but not FR1 then
301 	   fr1_mode must become FRE.  */
302 	if (in_req.fre && !in_req.fr1)
303 	  fr1_mode |= PR_FP_MODE_FRE;
304 
305 	/* Set the new mode.  Use fr1_mode if the requirements cannot be met by
306 	   FR0.  */
307 	if (!in_req.fr0)
308 	  return __prctl (PR_SET_FP_MODE, fr1_mode) != 0;
309 	else if (__prctl (PR_SET_FP_MODE, /* fr0_mode */ 0) != 0)
310 	  {
311 	    /* Setting FR0 can validly fail on an R6 core so retry with the FR1
312 	       mode as a fall back.  */
313 	    if (errno != ENOTSUP)
314 	      return true;
315 
316 	    return __prctl (PR_SET_FP_MODE, fr1_mode) != 0;
317 	  }
318       }
319 # endif /* HAVE_PRCTL_FP_MODE */
320     }
321 #endif /* _MIPS_SIM == _ABIO32 */
322 
323   return false;
324 }
325 
326 #endif /* dl-machine-reject-phdr.h */
327