blob: 9990b4df9c51712fe2574556e33037ad105faf1f [file] [log] [blame]
njn91772d12009-01-21 02:26:56 +00001
2/*--------------------------------------------------------------------*/
3/*--- User-mode execve(), and other stuff shared between stage1 ---*/
4/*--- and stage2. m_ume.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
Elliott Hughesed398002017-06-21 14:41:24 -070011 Copyright (C) 2000-2017 Julian Seward
njn91772d12009-01-21 02:26:56 +000012 jseward@acm.org
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
32
33#include "pub_core_basics.h"
34#include "pub_core_vki.h"
35
36#include "pub_core_libcbase.h"
37#include "pub_core_libcassert.h" // VG_(exit), vg_assert
38#include "pub_core_libcfile.h" // VG_(close) et al
39#include "pub_core_libcprint.h" // VG_(message)
40#include "pub_core_mallocfree.h" // VG_(strdup)
41#include "pub_core_syscall.h" // VG_(mk_SysRes_Error)
42#include "pub_core_options.h" // VG_(clo_xml)
43#include "pub_core_ume.h" // self
44
45#include "priv_ume.h"
46
47
48typedef struct {
florianff4a0842015-04-08 19:01:15 +000049 Bool (*match_fn)(const void *hdr, SizeT len);
njn91772d12009-01-21 02:26:56 +000050 Int (*load_fn)(Int fd, const HChar *name, ExeInfo *info);
51} ExeHandler;
52
53static ExeHandler exe_handlers[] = {
sewardj8eb8bab2015-07-21 14:44:28 +000054# if defined(VGO_linux) || defined(VGO_solaris)
njn8b68b642009-06-24 00:37:09 +000055 { VG_(match_ELF), VG_(load_ELF) },
sewardj6e9de462011-06-28 07:25:29 +000056# elif defined(VGO_darwin)
njn8b68b642009-06-24 00:37:09 +000057 { VG_(match_macho), VG_(load_macho) },
sewardj6e9de462011-06-28 07:25:29 +000058# else
59# error "unknown OS"
60# endif
njn8b68b642009-06-24 00:37:09 +000061 { VG_(match_script), VG_(load_script) },
njn91772d12009-01-21 02:26:56 +000062};
63#define EXE_HANDLER_COUNT (sizeof(exe_handlers)/sizeof(exe_handlers[0]))
64
65
66// Check the file looks executable.
67SysRes
68VG_(pre_exec_check)(const HChar* exe_name, Int* out_fd, Bool allow_setuid)
69{
70 Int fd, ret, i;
71 SysRes res;
72 Char buf[4096];
florianff4a0842015-04-08 19:01:15 +000073 SizeT bufsz = sizeof buf, fsz;
njn91772d12009-01-21 02:26:56 +000074 Bool is_setuid = False;
75
76 // Check it's readable
77 res = VG_(open)(exe_name, VKI_O_RDONLY, 0);
njncda2f0f2009-05-18 02:12:08 +000078 if (sr_isError(res)) {
njn91772d12009-01-21 02:26:56 +000079 return res;
80 }
njncda2f0f2009-05-18 02:12:08 +000081 fd = sr_Res(res);
njn91772d12009-01-21 02:26:56 +000082
83 // Check we have execute permissions
florian0af78ad2012-11-03 18:28:20 +000084 ret = VG_(check_executable)(&is_setuid, exe_name, allow_setuid);
njn91772d12009-01-21 02:26:56 +000085 if (0 != ret) {
86 VG_(close)(fd);
87 if (is_setuid && !VG_(clo_xml)) {
sewardj738856f2009-07-15 14:48:32 +000088 VG_(message)(Vg_UserMsg, "\n");
njn91772d12009-01-21 02:26:56 +000089 VG_(message)(Vg_UserMsg,
tomb7c2f9d2014-05-22 08:57:06 +000090 "Warning: Can't execute setuid/setgid/setcap executable: %s\n",
njn91772d12009-01-21 02:26:56 +000091 exe_name);
92 VG_(message)(Vg_UserMsg, "Possible workaround: remove "
sewardj738856f2009-07-15 14:48:32 +000093 "--trace-children=yes, if in effect\n");
94 VG_(message)(Vg_UserMsg, "\n");
njn91772d12009-01-21 02:26:56 +000095 }
96 return VG_(mk_SysRes_Error)(ret);
97 }
98
99 fsz = (SizeT)VG_(fsize)(fd);
100 if (fsz < bufsz)
101 bufsz = fsz;
102
103 res = VG_(pread)(fd, buf, bufsz, 0);
njncda2f0f2009-05-18 02:12:08 +0000104 if (sr_isError(res) || sr_Res(res) != bufsz) {
njn91772d12009-01-21 02:26:56 +0000105 VG_(close)(fd);
106 return VG_(mk_SysRes_Error)(VKI_EACCES);
107 }
njncda2f0f2009-05-18 02:12:08 +0000108 bufsz = sr_Res(res);
njn91772d12009-01-21 02:26:56 +0000109
110 // Look for a matching executable format
111 for (i = 0; i < EXE_HANDLER_COUNT; i++) {
112 if ((*exe_handlers[i].match_fn)(buf, bufsz)) {
113 res = VG_(mk_SysRes_Success)(i);
114 break;
115 }
116 }
117 if (i == EXE_HANDLER_COUNT) {
118 // Rejected by all executable format handlers.
119 res = VG_(mk_SysRes_Error)(VKI_ENOEXEC);
120 }
121
122 // Write the 'out_fd' param if necessary, or close the file.
njncda2f0f2009-05-18 02:12:08 +0000123 if (!sr_isError(res) && out_fd) {
njn91772d12009-01-21 02:26:56 +0000124 *out_fd = fd;
125 } else {
126 VG_(close)(fd);
127 }
128
129 return res;
130}
131
132// returns: 0 = success, non-0 is failure
133//
134// We can execute only binaries (ELF, etc) or scripts that begin with "#!".
florianff4a0842015-04-08 19:01:15 +0000135// (Not, for example, scripts that don't begin with "#!"; see
136// do_exec_shell_followup for how that's handled.)
njn91772d12009-01-21 02:26:56 +0000137Int VG_(do_exec_inner)(const HChar* exe, ExeInfo* info)
138{
139 SysRes res;
140 Int fd;
141 Int ret;
142
143 res = VG_(pre_exec_check)(exe, &fd, False/*allow_setuid*/);
njncda2f0f2009-05-18 02:12:08 +0000144 if (sr_isError(res))
145 return sr_Err(res);
njn91772d12009-01-21 02:26:56 +0000146
njncda2f0f2009-05-18 02:12:08 +0000147 vg_assert2(sr_Res(res) >= 0 && sr_Res(res) < EXE_HANDLER_COUNT,
njn91772d12009-01-21 02:26:56 +0000148 "invalid VG_(pre_exec_check) result");
149
njncda2f0f2009-05-18 02:12:08 +0000150 ret = (*exe_handlers[sr_Res(res)].load_fn)(fd, exe, info);
njn91772d12009-01-21 02:26:56 +0000151
152 VG_(close)(fd);
153
154 return ret;
155}
156
157
florian0af78ad2012-11-03 18:28:20 +0000158static Bool is_hash_bang_file(const HChar* f)
njn91772d12009-01-21 02:26:56 +0000159{
160 SysRes res = VG_(open)(f, VKI_O_RDONLY, 0);
njncda2f0f2009-05-18 02:12:08 +0000161 if (!sr_isError(res)) {
florian0af78ad2012-11-03 18:28:20 +0000162 HChar buf[3] = {0,0,0};
njncda2f0f2009-05-18 02:12:08 +0000163 Int fd = sr_Res(res);
njn91772d12009-01-21 02:26:56 +0000164 Int n = VG_(read)(fd, buf, 2);
165 if (n == 2 && VG_STREQ("#!", buf))
166 return True;
167 }
168 return False;
169}
170
171// Look at the first 80 chars, and if any are greater than 127, it's binary.
172// This is crude, but should be good enough. Note that it fails on a
173// zero-length file, as we want.
florian0af78ad2012-11-03 18:28:20 +0000174static Bool is_binary_file(const HChar* f)
njn91772d12009-01-21 02:26:56 +0000175{
176 SysRes res = VG_(open)(f, VKI_O_RDONLY, 0);
njncda2f0f2009-05-18 02:12:08 +0000177 if (!sr_isError(res)) {
njn91772d12009-01-21 02:26:56 +0000178 UChar buf[80];
njncda2f0f2009-05-18 02:12:08 +0000179 Int fd = sr_Res(res);
njn91772d12009-01-21 02:26:56 +0000180 Int n = VG_(read)(fd, buf, 80);
181 Int i;
182 for (i = 0; i < n; i++) {
183 if (buf[i] > 127)
184 return True; // binary char found
185 }
186 return False;
187 } else {
188 // Something went wrong. This will only happen if we earlier
189 // succeeded in opening the file but fail here (eg. the file was
190 // deleted between then and now).
njnb1cc5d62010-07-06 04:05:23 +0000191 VG_(fmsg)("%s: unknown error\n", f);
njn91772d12009-01-21 02:26:56 +0000192 VG_(exit)(126); // 126 == NOEXEC
193 }
194}
195
196// If the do_exec fails we try to emulate what the shell does (I used
197// bash as a guide). It's worth noting that the shell can execute some
198// things that VG_(do_exec)() (which subsitutes for the kernel's exec())
199// will refuse to (eg. scripts lacking a "#!" prefix).
florian0af78ad2012-11-03 18:28:20 +0000200static Int do_exec_shell_followup(Int ret, const HChar* exe_name, ExeInfo* info)
njn91772d12009-01-21 02:26:56 +0000201{
sewardj26ed4192014-11-04 17:44:21 +0000202# if defined(VGPV_arm_linux_android) \
203 || defined(VGPV_x86_linux_android) \
204 || defined(VGPV_mips32_linux_android) \
205 || defined(VGPV_arm64_linux_android)
florian0af78ad2012-11-03 18:28:20 +0000206 const HChar* default_interp_name = "/system/bin/sh";
sewardj51381112011-07-12 06:19:05 +0000207# else
florian0af78ad2012-11-03 18:28:20 +0000208 const HChar* default_interp_name = "/bin/sh";
sewardj51381112011-07-12 06:19:05 +0000209# endif
210
njn91772d12009-01-21 02:26:56 +0000211 SysRes res;
212 struct vg_stat st;
213
214 if (VKI_ENOEXEC == ret) {
215 // It was an executable file, but in an unacceptable format. Probably
216 // is a shell script lacking the "#!" prefix; try to execute it so.
217
218 // Is it a binary file?
219 if (is_binary_file(exe_name)) {
njnb1cc5d62010-07-06 04:05:23 +0000220 VG_(fmsg)("%s: cannot execute binary file\n", exe_name);
njn91772d12009-01-21 02:26:56 +0000221 VG_(exit)(126); // 126 == NOEXEC
222 }
223
224 // Looks like a script. Run it with /bin/sh. This includes
225 // zero-length files.
Elliott Hughesa0664b92017-04-18 17:46:52 -0700226 VG_(free)(info->interp_name);
njn91772d12009-01-21 02:26:56 +0000227 info->interp_name = VG_(strdup)("ume.desf.1", default_interp_name);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700228 VG_(free)(info->interp_args); info->interp_args = NULL;
njn91772d12009-01-21 02:26:56 +0000229 if (info->argv && info->argv[0] != NULL)
florian3e798632012-11-24 19:41:54 +0000230 info->argv[0] = exe_name;
njn91772d12009-01-21 02:26:56 +0000231
232 ret = VG_(do_exec_inner)(info->interp_name, info);
233
234 if (0 != ret) {
235 // Something went wrong with executing the default interpreter
njnb1cc5d62010-07-06 04:05:23 +0000236 VG_(fmsg)("%s: bad interpreter (%s): %s\n",
njn91772d12009-01-21 02:26:56 +0000237 exe_name, info->interp_name, VG_(strerror)(ret));
238 VG_(exit)(126); // 126 == NOEXEC
239 }
240
241 } else if (0 != ret) {
242 // Something else went wrong. Try to make the error more specific,
243 // and then print a message and abort.
florianff4a0842015-04-08 19:01:15 +0000244 Int exit_code = 126; // 126 == NOEXEC (bash)
245
njn91772d12009-01-21 02:26:56 +0000246 res = VG_(stat)(exe_name, &st);
florianff4a0842015-04-08 19:01:15 +0000247
248 // Does the file exist ?
249 if (sr_isError(res) && sr_Err(res) == VKI_ENOENT) {
250 VG_(fmsg)("%s: %s\n", exe_name, VG_(strerror)(ret));
251 exit_code = 127; // 127 == NOTFOUND (bash)
252
253 // Was it a directory?
254 } else if (!sr_isError(res) && VKI_S_ISDIR(st.mode)) {
njnb1cc5d62010-07-06 04:05:23 +0000255 VG_(fmsg)("%s: is a directory\n", exe_name);
njn91772d12009-01-21 02:26:56 +0000256
257 // Was it not executable?
258 } else if (0 != VG_(check_executable)(NULL, exe_name,
259 False/*allow_setuid*/)) {
njnb1cc5d62010-07-06 04:05:23 +0000260 VG_(fmsg)("%s: %s\n", exe_name, VG_(strerror)(ret));
njn91772d12009-01-21 02:26:56 +0000261
262 // Did it start with "#!"? If so, it must have been a bad interpreter.
263 } else if (is_hash_bang_file(exe_name)) {
njnb1cc5d62010-07-06 04:05:23 +0000264 VG_(fmsg)("%s: bad interpreter: %s\n", exe_name, VG_(strerror)(ret));
njn91772d12009-01-21 02:26:56 +0000265
266 // Otherwise it was something else.
267 } else {
njnb1cc5d62010-07-06 04:05:23 +0000268 VG_(fmsg)("%s: %s\n", exe_name, VG_(strerror)(ret));
njn91772d12009-01-21 02:26:56 +0000269 }
florianff4a0842015-04-08 19:01:15 +0000270 VG_(exit)(exit_code);
njn91772d12009-01-21 02:26:56 +0000271 }
272 return ret;
273}
274
275
276// This emulates the kernel's exec(). If it fails, it then emulates the
277// shell's handling of the situation.
florianff4a0842015-04-08 19:01:15 +0000278// See pub_core_ume.h for an indication of which entries of 'info' are
279// inputs, which are outputs, and which are both.
njn91772d12009-01-21 02:26:56 +0000280/* returns: 0 = success, non-0 is failure */
281Int VG_(do_exec)(const HChar* exe_name, ExeInfo* info)
282{
283 Int ret;
Elliott Hughesa0664b92017-04-18 17:46:52 -0700284
285 VG_(free)(info->interp_name); info->interp_name = NULL;
286 VG_(free)(info->interp_args); info->interp_args = NULL;
njn91772d12009-01-21 02:26:56 +0000287
288 ret = VG_(do_exec_inner)(exe_name, info);
289
290 if (0 != ret) {
florian0af78ad2012-11-03 18:28:20 +0000291 ret = do_exec_shell_followup(ret, exe_name, info);
njn91772d12009-01-21 02:26:56 +0000292 }
293 return ret;
294}
295
296/*--------------------------------------------------------------------*/
297/*--- end ---*/
298/*--------------------------------------------------------------------*/