florian | 512f27e | 2015-07-21 21:37:23 +0000 | [diff] [blame] | 1 | /* -*- mode: C; c-basic-offset: 3; -*- */ |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 2 | |
| 3 | /*--------------------------------------------------------------------*/ |
| 4 | /*--- User-mode execve() for #! scripts. m_ume_script.c ---*/ |
| 5 | /*--------------------------------------------------------------------*/ |
| 6 | |
| 7 | /* |
| 8 | This file is part of Valgrind, a dynamic binary instrumentation |
| 9 | framework. |
| 10 | |
sewardj | b3a1e4b | 2015-08-21 11:32:26 +0000 | [diff] [blame] | 11 | Copyright (C) 2000-2015 Julian Seward |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 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 | #include "pub_core_basics.h" |
| 33 | #include "pub_core_vki.h" |
| 34 | |
| 35 | #include "pub_core_libcbase.h" |
njn | 5ec1a17 | 2009-05-19 05:52:29 +0000 | [diff] [blame] | 36 | #include "pub_core_libcassert.h" // VG_(exit), vg_assert |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 37 | #include "pub_core_libcfile.h" // VG_(close) et al |
| 38 | #include "pub_core_libcprint.h" |
florian | ff4a084 | 2015-04-08 19:01:15 +0000 | [diff] [blame] | 39 | #include "pub_core_clientstate.h" // VG_(args_the_exename) |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 40 | #include "pub_core_mallocfree.h" // VG_(strdup) |
| 41 | #include "pub_core_ume.h" // self |
| 42 | |
njn | 5ec1a17 | 2009-05-19 05:52:29 +0000 | [diff] [blame] | 43 | #include "priv_ume.h" |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 44 | |
florian | 512f27e | 2015-07-21 21:37:23 +0000 | [diff] [blame] | 45 | /* Return true, if the first line begins with #! and contains an |
| 46 | interpreter. */ |
florian | ff4a084 | 2015-04-08 19:01:15 +0000 | [diff] [blame] | 47 | Bool VG_(match_script)(const void *hdr, SizeT len) |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 48 | { |
florian | 0af78ad | 2012-11-03 18:28:20 +0000 | [diff] [blame] | 49 | const HChar* script = hdr; |
| 50 | const HChar* end = script + len; |
| 51 | const HChar* interp = script + 2; |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 52 | |
florian | 512f27e | 2015-07-21 21:37:23 +0000 | [diff] [blame] | 53 | if (len < 2) return False; |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 54 | if (0 != VG_(memcmp)(hdr, "#!", 2)) return False; |
| 55 | |
florian | 512f27e | 2015-07-21 21:37:23 +0000 | [diff] [blame] | 56 | // Find interpreter name, which may be absolute or relative. |
| 57 | // First, skip over any space between the #! and the start of the |
| 58 | // interpreter name |
florian | e4a4c57 | 2015-04-02 16:07:41 +0000 | [diff] [blame] | 59 | while (interp < end && (*interp == ' ' || *interp == '\t')) interp++; |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 60 | |
| 61 | // overrun? |
| 62 | if (interp >= end) return False; // can't find start of interp name |
| 63 | |
florian | 512f27e | 2015-07-21 21:37:23 +0000 | [diff] [blame] | 64 | // No interpreter found. |
| 65 | if (*interp == '\n') return False; |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 66 | |
| 67 | return True; // looks like a #! script |
| 68 | } |
| 69 | |
| 70 | |
| 71 | /* returns: 0 = success, non-0 is failure */ |
| 72 | Int VG_(load_script)(Int fd, const HChar* name, ExeInfo* info) |
| 73 | { |
florian | 0af78ad | 2012-11-03 18:28:20 +0000 | [diff] [blame] | 74 | HChar hdr[4096]; |
florian | ff4a084 | 2015-04-08 19:01:15 +0000 | [diff] [blame] | 75 | Int len = sizeof hdr; |
florian | 0af78ad | 2012-11-03 18:28:20 +0000 | [diff] [blame] | 76 | Int eol; |
| 77 | HChar* interp; |
| 78 | HChar* end; |
| 79 | HChar* cp; |
| 80 | HChar* arg = NULL; |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 81 | SysRes res; |
| 82 | |
| 83 | // Read the first part of the file. |
| 84 | res = VG_(pread)(fd, hdr, len, 0); |
njn | cda2f0f | 2009-05-18 02:12:08 +0000 | [diff] [blame] | 85 | if (sr_isError(res)) { |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 86 | VG_(close)(fd); |
| 87 | return VKI_EACCES; |
| 88 | } else { |
njn | cda2f0f | 2009-05-18 02:12:08 +0000 | [diff] [blame] | 89 | len = sr_Res(res); |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 90 | } |
| 91 | |
| 92 | vg_assert('#' == hdr[0] && '!' == hdr[1]); |
| 93 | |
| 94 | end = hdr + len; |
| 95 | interp = hdr + 2; |
florian | ff4a084 | 2015-04-08 19:01:15 +0000 | [diff] [blame] | 96 | while (interp < end && (*interp == ' ' || *interp == '\t')) |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 97 | interp++; |
| 98 | |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 99 | /* skip over interpreter name */ |
| 100 | for (cp = interp; cp < end && !VG_(isspace)(*cp); cp++) |
| 101 | ; |
| 102 | |
| 103 | eol = (*cp == '\n'); |
| 104 | |
| 105 | *cp++ = '\0'; |
| 106 | |
| 107 | if (!eol && cp < end) { |
| 108 | /* skip space before arg */ |
| 109 | while (cp < end && VG_(isspace)(*cp) && *cp != '\n') |
| 110 | cp++; |
| 111 | |
| 112 | /* arg is from here to eol */ |
| 113 | arg = cp; |
| 114 | while (cp < end && *cp != '\n') |
| 115 | cp++; |
| 116 | *cp = '\0'; |
| 117 | } |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame^] | 118 | VG_(free)(info->interp_name); |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 119 | info->interp_name = VG_(strdup)("ume.ls.1", interp); |
| 120 | vg_assert(NULL != info->interp_name); |
| 121 | if (arg != NULL && *arg != '\0') { |
| 122 | info->interp_args = VG_(strdup)("ume.ls.2", arg); |
| 123 | vg_assert(NULL != info->interp_args); |
| 124 | } |
| 125 | |
| 126 | if (info->argv && info->argv[0] != NULL) |
florian | 3e79863 | 2012-11-24 19:41:54 +0000 | [diff] [blame] | 127 | info->argv[0] = name; |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 128 | |
tom | 892af32 | 2010-05-25 08:45:44 +0000 | [diff] [blame] | 129 | VG_(args_the_exename) = name; |
| 130 | |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 131 | if (0) |
| 132 | VG_(printf)("#! script: interp_name=\"%s\" interp_args=\"%s\"\n", |
| 133 | info->interp_name, info->interp_args); |
| 134 | |
| 135 | return VG_(do_exec_inner)(interp, info); |
| 136 | } |
| 137 | |
njn | 91772d1 | 2009-01-21 02:26:56 +0000 | [diff] [blame] | 138 | /*--------------------------------------------------------------------*/ |
| 139 | /*--- end ---*/ |
| 140 | /*--------------------------------------------------------------------*/ |