• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
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 
11    Copyright (C) 2000-2013 Julian Seward
12       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 
48 typedef struct {
49    Bool (*match_fn)(const void *hdr, Int len);
50    Int  (*load_fn)(Int fd, const HChar *name, ExeInfo *info);
51 } ExeHandler;
52 
53 static ExeHandler exe_handlers[] = {
54 #  if defined(VGO_linux)
55    { VG_(match_ELF),    VG_(load_ELF) },
56 #  elif defined(VGO_darwin)
57    { VG_(match_macho),  VG_(load_macho) },
58 #  else
59 #    error "unknown OS"
60 #  endif
61    { VG_(match_script), VG_(load_script) },
62 };
63 #define EXE_HANDLER_COUNT (sizeof(exe_handlers)/sizeof(exe_handlers[0]))
64 
65 
66 // Check the file looks executable.
67 SysRes
VG_(pre_exec_check)68 VG_(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];
73    SizeT bufsz = 4096, fsz;
74    Bool is_setuid = False;
75 
76    // Check it's readable
77    res = VG_(open)(exe_name, VKI_O_RDONLY, 0);
78    if (sr_isError(res)) {
79       return res;
80    }
81    fd = sr_Res(res);
82 
83    // Check we have execute permissions
84    ret = VG_(check_executable)(&is_setuid, exe_name, allow_setuid);
85    if (0 != ret) {
86       VG_(close)(fd);
87       if (is_setuid && !VG_(clo_xml)) {
88          VG_(message)(Vg_UserMsg, "\n");
89          VG_(message)(Vg_UserMsg,
90                       "Warning: Can't execute setuid/setgid/setcap executable: %s\n",
91                       exe_name);
92          VG_(message)(Vg_UserMsg, "Possible workaround: remove "
93                       "--trace-children=yes, if in effect\n");
94          VG_(message)(Vg_UserMsg, "\n");
95       }
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);
104    if (sr_isError(res) || sr_Res(res) != bufsz) {
105       VG_(close)(fd);
106       return VG_(mk_SysRes_Error)(VKI_EACCES);
107    }
108    bufsz = sr_Res(res);
109 
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.
123    if (!sr_isError(res) && out_fd) {
124       *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 "#!".
135 // (Not, for example, scripts that don't begin with "#!";  see the
136 // VG_(do_exec)() invocation from m_main.c for how that's handled.)
VG_(do_exec_inner)137 Int 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*/);
144    if (sr_isError(res))
145       return sr_Err(res);
146 
147    vg_assert2(sr_Res(res) >= 0 && sr_Res(res) < EXE_HANDLER_COUNT,
148               "invalid VG_(pre_exec_check) result");
149 
150    ret = (*exe_handlers[sr_Res(res)].load_fn)(fd, exe, info);
151 
152    VG_(close)(fd);
153 
154    return ret;
155 }
156 
157 
is_hash_bang_file(const HChar * f)158 static Bool is_hash_bang_file(const HChar* f)
159 {
160    SysRes res = VG_(open)(f, VKI_O_RDONLY, 0);
161    if (!sr_isError(res)) {
162       HChar buf[3] = {0,0,0};
163       Int fd = sr_Res(res);
164       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.
is_binary_file(const HChar * f)174 static Bool is_binary_file(const HChar* f)
175 {
176    SysRes res = VG_(open)(f, VKI_O_RDONLY, 0);
177    if (!sr_isError(res)) {
178       UChar buf[80];
179       Int fd = sr_Res(res);
180       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).
191       VG_(fmsg)("%s: unknown error\n", f);
192       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).
do_exec_shell_followup(Int ret,const HChar * exe_name,ExeInfo * info)200 static Int do_exec_shell_followup(Int ret, const HChar* exe_name, ExeInfo* info)
201 {
202 #  if defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android) \
203       || defined(VGPV_mips32_linux_android)
204    const HChar*  default_interp_name = "/system/bin/sh";
205 #  else
206    const HChar*  default_interp_name = "/bin/sh";
207 #  endif
208 
209    SysRes res;
210    struct vg_stat st;
211 
212    if (VKI_ENOEXEC == ret) {
213       // It was an executable file, but in an unacceptable format.  Probably
214       // is a shell script lacking the "#!" prefix;  try to execute it so.
215 
216       // Is it a binary file?
217       if (is_binary_file(exe_name)) {
218          VG_(fmsg)("%s: cannot execute binary file\n", exe_name);
219          VG_(exit)(126);      // 126 == NOEXEC
220       }
221 
222       // Looks like a script.  Run it with /bin/sh.  This includes
223       // zero-length files.
224 
225       info->interp_name = VG_(strdup)("ume.desf.1", default_interp_name);
226       info->interp_args = NULL;
227       if (info->argv && info->argv[0] != NULL)
228          info->argv[0] = exe_name;
229 
230       ret = VG_(do_exec_inner)(info->interp_name, info);
231 
232       if (0 != ret) {
233          // Something went wrong with executing the default interpreter
234          VG_(fmsg)("%s: bad interpreter (%s): %s\n",
235                      exe_name, info->interp_name, VG_(strerror)(ret));
236          VG_(exit)(126);      // 126 == NOEXEC
237       }
238 
239    } else if (0 != ret) {
240       // Something else went wrong.  Try to make the error more specific,
241       // and then print a message and abort.
242 
243       // Was it a directory?
244       res = VG_(stat)(exe_name, &st);
245       if (!sr_isError(res) && VKI_S_ISDIR(st.mode)) {
246          VG_(fmsg)("%s: is a directory\n", exe_name);
247 
248       // Was it not executable?
249       } else if (0 != VG_(check_executable)(NULL, exe_name,
250                                             False/*allow_setuid*/)) {
251          VG_(fmsg)("%s: %s\n", exe_name, VG_(strerror)(ret));
252 
253       // Did it start with "#!"?  If so, it must have been a bad interpreter.
254       } else if (is_hash_bang_file(exe_name)) {
255          VG_(fmsg)("%s: bad interpreter: %s\n", exe_name, VG_(strerror)(ret));
256 
257       // Otherwise it was something else.
258       } else {
259          VG_(fmsg)("%s: %s\n", exe_name, VG_(strerror)(ret));
260       }
261       // 126 means NOEXEC;  I think this is Posix, and that in some cases we
262       // should be returning 127, meaning NOTFOUND.  Oh well.
263       VG_(exit)(126);
264    }
265    return ret;
266 }
267 
268 
269 // This emulates the kernel's exec().  If it fails, it then emulates the
270 // shell's handling of the situation.
271 // See ume.h for an indication of which entries of 'info' are inputs, which
272 // are outputs, and which are both.
273 /* returns: 0 = success, non-0 is failure */
VG_(do_exec)274 Int VG_(do_exec)(const HChar* exe_name, ExeInfo* info)
275 {
276    Int ret;
277 
278    info->interp_name = NULL;
279    info->interp_args = NULL;
280 
281    ret = VG_(do_exec_inner)(exe_name, info);
282 
283    if (0 != ret) {
284       ret = do_exec_shell_followup(ret, exe_name, info);
285    }
286    return ret;
287 }
288 
289 /*--------------------------------------------------------------------*/
290 /*--- end                                                          ---*/
291 /*--------------------------------------------------------------------*/
292