Home | History | Annotate | Download | only in m_ume
      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-2012 Julian Seward
     12       jseward (at) 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)(Char *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
     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, (HChar*)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 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.)
    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 
    158 static Bool is_hash_bang_file(Char* f)
    159 {
    160    SysRes res = VG_(open)(f, VKI_O_RDONLY, 0);
    161    if (!sr_isError(res)) {
    162       Char 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.
    174 static Bool is_binary_file(Char* 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).
    200 static Int do_exec_shell_followup(Int ret, HChar* exe_name, ExeInfo* info)
    201 {
    202 #  if defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android)
    203    Char*  default_interp_name = "/system/bin/sh";
    204 #  else
    205    Char*  default_interp_name = "/bin/sh";
    206 #  endif
    207 
    208    SysRes res;
    209    struct vg_stat st;
    210 
    211    if (VKI_ENOEXEC == ret) {
    212       // It was an executable file, but in an unacceptable format.  Probably
    213       // is a shell script lacking the "#!" prefix;  try to execute it so.
    214 
    215       // Is it a binary file?
    216       if (is_binary_file(exe_name)) {
    217          VG_(fmsg)("%s: cannot execute binary file\n", exe_name);
    218          VG_(exit)(126);      // 126 == NOEXEC
    219       }
    220 
    221       // Looks like a script.  Run it with /bin/sh.  This includes
    222       // zero-length files.
    223 
    224       info->interp_name = VG_(strdup)("ume.desf.1", default_interp_name);
    225       info->interp_args = NULL;
    226       if (info->argv && info->argv[0] != NULL)
    227          info->argv[0] = (char *)exe_name;
    228 
    229       ret = VG_(do_exec_inner)(info->interp_name, info);
    230 
    231       if (0 != ret) {
    232          // Something went wrong with executing the default interpreter
    233          VG_(fmsg)("%s: bad interpreter (%s): %s\n",
    234                      exe_name, info->interp_name, VG_(strerror)(ret));
    235          VG_(exit)(126);      // 126 == NOEXEC
    236       }
    237 
    238    } else if (0 != ret) {
    239       // Something else went wrong.  Try to make the error more specific,
    240       // and then print a message and abort.
    241 
    242       // Was it a directory?
    243       res = VG_(stat)(exe_name, &st);
    244       if (!sr_isError(res) && VKI_S_ISDIR(st.mode)) {
    245          VG_(fmsg)("%s: is a directory\n", exe_name);
    246 
    247       // Was it not executable?
    248       } else if (0 != VG_(check_executable)(NULL, exe_name,
    249                                             False/*allow_setuid*/)) {
    250          VG_(fmsg)("%s: %s\n", exe_name, VG_(strerror)(ret));
    251 
    252       // Did it start with "#!"?  If so, it must have been a bad interpreter.
    253       } else if (is_hash_bang_file(exe_name)) {
    254          VG_(fmsg)("%s: bad interpreter: %s\n", exe_name, VG_(strerror)(ret));
    255 
    256       // Otherwise it was something else.
    257       } else {
    258          VG_(fmsg)("%s: %s\n", exe_name, VG_(strerror)(ret));
    259       }
    260       // 126 means NOEXEC;  I think this is Posix, and that in some cases we
    261       // should be returning 127, meaning NOTFOUND.  Oh well.
    262       VG_(exit)(126);
    263    }
    264    return ret;
    265 }
    266 
    267 
    268 // This emulates the kernel's exec().  If it fails, it then emulates the
    269 // shell's handling of the situation.
    270 // See ume.h for an indication of which entries of 'info' are inputs, which
    271 // are outputs, and which are both.
    272 /* returns: 0 = success, non-0 is failure */
    273 Int VG_(do_exec)(const HChar* exe_name, ExeInfo* info)
    274 {
    275    Int ret;
    276 
    277    info->interp_name = NULL;
    278    info->interp_args = NULL;
    279 
    280    ret = VG_(do_exec_inner)(exe_name, info);
    281 
    282    if (0 != ret) {
    283       Char* exe_name_casted = (Char*)exe_name;
    284       ret = do_exec_shell_followup(ret, exe_name_casted, info);
    285    }
    286    return ret;
    287 }
    288 
    289 /*--------------------------------------------------------------------*/
    290 /*--- end                                                          ---*/
    291 /*--------------------------------------------------------------------*/
    292