|
From: <sv...@va...> - 2005-10-14 03:11:38
|
Author: njn
Date: 2005-10-14 04:11:30 +0100 (Fri, 14 Oct 2005)
New Revision: 4918
Log:
Overhaul the way programs are loaded at startup and exec() works. Now th=
e
checking of programs done in these two places are combined, which avoids
duplicate code and greatly reduces the number of cases in which exec()
fails causing Valgrind to bomb out.
Also, we can now load some programs we could not previously, such as scri=
pts
lacking a "#!" line at the start. Also, the startup failure messages for
bad programs match the shell's messages very closely.
And I added a whole bunch of regtests to test all this.
Added:
trunk/none/tests/shell
trunk/none/tests/shell.stderr.exp
trunk/none/tests/shell.stdout.exp
trunk/none/tests/shell.vgtest
trunk/none/tests/shell_badinterp
trunk/none/tests/shell_badinterp.stderr.exp
trunk/none/tests/shell_badinterp.vgtest
trunk/none/tests/shell_binaryfile
trunk/none/tests/shell_binaryfile.stderr.exp
trunk/none/tests/shell_binaryfile.vgtest
trunk/none/tests/shell_dir.stderr.exp
trunk/none/tests/shell_dir.vgtest
trunk/none/tests/shell_nonexec.stderr.exp
trunk/none/tests/shell_nonexec.vgtest
trunk/none/tests/shell_nosuchfile.stderr.exp
trunk/none/tests/shell_nosuchfile.vgtest
trunk/none/tests/shell_valid1
trunk/none/tests/shell_valid1.stderr.exp
trunk/none/tests/shell_valid1.vgtest
trunk/none/tests/shell_valid2
trunk/none/tests/shell_valid2.stderr.exp
trunk/none/tests/shell_valid2.vgtest
trunk/none/tests/shell_valid3
trunk/none/tests/shell_valid3.stderr.exp
trunk/none/tests/shell_valid3.vgtest
trunk/none/tests/shell_zerolength
trunk/none/tests/shell_zerolength.stderr.exp
trunk/none/tests/shell_zerolength.vgtest
Modified:
trunk/coregrind/m_libcfile.c
trunk/coregrind/m_main.c
trunk/coregrind/m_syswrap/syswrap-generic.c
trunk/coregrind/m_ume.c
trunk/coregrind/pub_core_libcfile.h
trunk/coregrind/pub_core_ume.h
trunk/none/tests/Makefile.am
trunk/none/tests/cmdline5.stderr.exp
trunk/none/tests/cmdline6.stderr.exp
Modified: trunk/coregrind/m_libcfile.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_libcfile.c 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/coregrind/m_libcfile.c 2005-10-14 03:11:30 UTC (rev 4918)
@@ -138,6 +138,14 @@
return res.isError ? (-1) : buf.st_size;
}
=20
+Bool VG_(is_dir) ( HChar* f )
+{
+ struct vki_stat buf;
+ SysRes res =3D VG_(do_syscall2)(__NR_stat, (UWord)f, (UWord)&buf);
+ return res.isError ? False
+ : VKI_S_ISDIR(buf.st_mode) ? True : False;
+}
+
SysRes VG_(dup) ( Int oldfd )
{
return VG_(do_syscall1)(__NR_dup, oldfd);
@@ -207,6 +215,66 @@
#endif
}
=20
+/*=20
+ Emulate the normal Unix permissions checking algorithm.
+
+ If owner matches, then use the owner permissions, else
+ if group matches, then use the group permissions, else
+ use other permissions.
+
+ Note that we can't deal with SUID/SGID, so we refuse to run them
+ (otherwise the executable may misbehave if it doesn't have the
+ permissions it thinks it does).
+*/
+/* returns: 0 =3D success, non-0 is failure */
+Int VG_(check_executable)(HChar* f)
+{
+ struct vki_stat st;
+ SysRes res;
+
+ res =3D VG_(stat)(f, &st);
+ if (res.isError) {
+ return res.val;
+ }
+
+ if (st.st_mode & (VKI_S_ISUID | VKI_S_ISGID)) {
+ //VG_(printf)("Can't execute suid/sgid executable %s\n", exe);
+ return VKI_EACCES;
+ }
+
+ if (VG_(geteuid)() =3D=3D st.st_uid) {
+ if (!(st.st_mode & VKI_S_IXUSR))
+ return VKI_EACCES;
+ } else {
+ int grpmatch =3D 0;
+
+ if (VG_(getegid)() =3D=3D st.st_gid)
+ grpmatch =3D 1;
+ else {
+ UInt groups[32];
+ Int ngrp =3D VG_(getgroups)(32, groups);
+ Int i;
+ /* ngrp will be -1 if VG_(getgroups) failed. */
+ for (i =3D 0; i < ngrp; i++) {
+ if (groups[i] =3D=3D st.st_gid) {
+ grpmatch =3D 1;
+ break;
+ }
+ }
+ }
+
+ if (grpmatch) {
+ if (!(st.st_mode & VKI_S_IXGRP)) {
+ return VKI_EACCES;
+ }
+ } else if (!(st.st_mode & VKI_S_IXOTH)) {
+ return VKI_EACCES;
+ }
+ }
+
+ return 0;
+}
+
SysRes VG_(pread) ( Int fd, void* buf, Int count, Int offset )
{
OffT off =3D VG_(lseek)( fd, (OffT)offset, VKI_SEEK_SET);
Modified: trunk/coregrind/m_main.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_main.c 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/coregrind/m_main.c 2005-10-14 03:11:30 UTC (rev 4918)
@@ -724,37 +724,56 @@
}
=20
/* Need a static copy because can't use dynamic mem allocation yet */
-static HChar executable_name[VKI_PATH_MAX];
+static HChar executable_name_in [VKI_PATH_MAX];
+static HChar executable_name_out[VKI_PATH_MAX];
=20
static Bool match_executable(const char *entry)=20
{
- HChar buf[VG_(strlen)(entry) + VG_(strlen)(executable_name) + 3];
+ HChar buf[VG_(strlen)(entry) + VG_(strlen)(executable_name_in) + 3];
=20
- /* empty PATH element means . */
+ /* empty PATH element means '.' */
if (*entry =3D=3D '\0')
entry =3D ".";
=20
- VG_(snprintf)(buf, sizeof(buf), "%s/%s", entry, executable_name);
+ VG_(snprintf)(buf, sizeof(buf), "%s/%s", entry, executable_name_in);
+
+ // Don't match directories
+ if (VG_(is_dir)(buf))
+ return False;
+
+ // If we match an executable, we choose that immediately. If we find=
a
+ // matching non-executable we remember it but keep looking for an
+ // matching executable later in the path.
if (VG_(access)(buf, True/*r*/, False/*w*/, True/*x*/) =3D=3D 0) {
- VG_(strncpy)( executable_name, buf, VKI_PATH_MAX-1 );
- executable_name[VKI_PATH_MAX-1] =3D 0;
- return True;
+ VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 );
+ executable_name_out[VKI_PATH_MAX-1] =3D 0;
+ return True; // Stop looking
+ } else if (VG_(access)(buf, True/*r*/, False/*w*/, False/*x*/) =3D=3D=
0=20
+ && VG_STREQ(executable_name_out, ""))=20
+ {
+ VG_(strncpy)( executable_name_out, buf, VKI_PATH_MAX-1 );
+ executable_name_out[VKI_PATH_MAX-1] =3D 0;
+ return False; // Keep looking
+ } else {=20
+ return False; // Keep looking
}
- return False;
}
=20
+// Returns NULL if it wasn't found.
static HChar* find_executable ( HChar* exec )
{
vg_assert(NULL !=3D exec);
- VG_(strncpy)( executable_name, exec, VKI_PATH_MAX-1 );
- executable_name[VKI_PATH_MAX-1] =3D 0;
-
- if (VG_(strchr)(executable_name, '/') =3D=3D NULL) {
- /* no '/' - we need to search the path */
+ if (VG_(strchr)(exec, '/')) {
+ // Has a '/' - use the name as is
+ VG_(strncpy)( executable_name_out, exec, VKI_PATH_MAX-1 );
+ } else {
+ // No '/' - we need to search the path
+ VG_(strncpy)( executable_name_in, exec, VKI_PATH_MAX-1 );
+ VG_(memset) ( executable_name_out, 0, VKI_PATH_MAX );
HChar *path =3D VG_(getenv)("PATH");
scan_colsep(path, match_executable);
}
- return executable_name;
+ return VG_STREQ(executable_name_out, "") ? NULL : executable_name_out=
;
}
=20
=20
@@ -802,27 +821,29 @@
static void load_client ( /*OUT*/struct exeinfo* info,=20
/*OUT*/Addr* client_eip)
{
- HChar* exec;
+ HChar* exe_name;
Int ret;
SysRes res;
=20
vg_assert( VG_(args_the_exename) !=3D NULL);
- exec =3D find_executable( VG_(args_the_exename) );
+ exe_name =3D find_executable( VG_(args_the_exename) );
=20
+ if (!exe_name) {
+ VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exen=
ame));
+ VG_(exit)(127); // 127 is Posix NOTFOUND
+ }
+
VG_(memset)(info, 0, sizeof(*info));
info->exe_base =3D VG_(client_base);
info->exe_end =3D VG_(client_end);
=20
- ret =3D VG_(do_exec)(exec, info);
- if (ret !=3D 0) {
- VG_(printf)("valgrind: do_exec(%s) failed: %s\n",
- exec, VG_(strerror)(ret));
- VG_(exit)(127);
- }
+ ret =3D VG_(do_exec)(exe_name, info);
=20
+ // The client was successfully loaded! Continue.
+
/* Get hold of a file descriptor which refers to the client
executable. This is needed for attaching to GDB. */
- res =3D VG_(open)(exec, VKI_O_RDONLY, VKI_S_IRUSR);
+ res =3D VG_(open)(exe_name, VKI_O_RDONLY, VKI_S_IRUSR);
if (!res.isError)
VG_(cl_exec_fd) =3D res.val;
=20
Modified: trunk/coregrind/m_syswrap/syswrap-generic.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_syswrap/syswrap-generic.c 2005-10-13 15:54:20 UTC (=
rev 4917)
+++ trunk/coregrind/m_syswrap/syswrap-generic.c 2005-10-14 03:11:30 UTC (=
rev 4918)
@@ -50,6 +50,7 @@
#include "pub_core_syscall.h"
#include "pub_core_syswrap.h"
#include "pub_core_tooliface.h"
+#include "pub_core_ume.h"
=20
#include "priv_types_n_macros.h"
#include "priv_syswrap-generic.h"
@@ -2288,6 +2289,7 @@
Char* launcher_basename =3D NULL;
ThreadState* tst;
Int i, j, tot_args;
+ SysRes res;
=20
PRINT("sys_execve ( %p(%s), %p, %p )", ARG1, ARG1, ARG2, ARG3);
PRE_REG_READ3(vki_off_t, "execve",
@@ -2307,31 +2309,21 @@
POST(execve), but that's close to impossible. Instead, we make
an effort to check that the execve will work before actually
doing it. */
- {
- struct vki_stat st;
- SysRes r =3D VG_(stat)((Char *)ARG1, &st);
=20
- if (r.isError) {
- /* stat failed */
- SET_STATUS_from_SysRes( r );
- return;
- }
- /* just look for regular file with any X bit set
- XXX do proper permissions check?
- */
- if ((st.st_mode & 0100111) =3D=3D 0100000) {
- SET_STATUS_Failure( VKI_EACCES );
- return;
- }
- }
-
- /* Check more .. that the name at least begins in client-accessible
- storage. */
+ /* Check that the name at least begins in client-accessible storage. =
*/
if (!VG_(am_is_valid_for_client)( ARG1, 1, VKI_PROT_READ )) {
SET_STATUS_Failure( VKI_EFAULT );
return;
}
=20
+ // Do the important checks: it is a file, is executable, permissions=
are
+ // ok, etc.
+ res =3D VG_(pre_exec_check)((const Char*)ARG1, NULL);
+ if (res.isError) {
+ SET_STATUS_Failure( res.val );
+ return;
+ }
+
/* If we're tracing the child, and the launcher name looks bogus
(possibly because launcher.c couldn't figure it out, see
comments therein) then we have no option but to fail. */
Modified: trunk/coregrind/m_ume.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_ume.c 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/coregrind/m_ume.c 2005-10-14 03:11:30 UTC (rev 4918)
@@ -38,6 +38,7 @@
// included ahead of the glibc ones. This fix is a kludge; the right
// solution is to entirely remove the glibc dependency.
#include "pub_core_basics.h"
+#include "pub_core_aspacemgr.h" // various mapping fns
#include "pub_core_debuglog.h"
#include "pub_core_libcbase.h"
#include "pub_core_machine.h"
@@ -45,9 +46,8 @@
#include "pub_core_libcfile.h" // VG_(close) et al
#include "pub_core_libcproc.h" // VG_(geteuid), VG_(getegid)
#include "pub_core_libcassert.h" // VG_(exit), vg_assert
-#include "pub_core_syscall.h" // VG_(strerror)
#include "pub_core_mallocfree.h" // VG_(malloc), VG_(free)
-#include "pub_core_aspacemgr.h" // various mapping fns
+#include "pub_core_syscall.h" // VG_(strerror)
#include "vki_unistd.h" // mmap-related constants
=20
#include "pub_core_ume.h"
@@ -65,7 +65,7 @@
{
ESZ(Ehdr) e;
ESZ(Phdr) *p;
- int fd;
+ Int fd;
};
=20
static void check_mmap(SysRes res, Addr base, SizeT len)
@@ -77,165 +77,6 @@
}
}
=20
-//zz // 'extra' allows the caller to pass in extra args to 'fn', like fr=
ee
-//zz // variables to a closure.
-//zz void VG_(foreach_map)(int (*fn)(char *start, char *end,
-//zz const char *perm, off_t offset,
-//zz int maj, int min, int ino, void* ex=
tra),
-//zz void* extra)
-//zz {
-//zz static char buf[10240];
-//zz char *bufptr =3D buf;
-//zz int ret, fd;
-//zz=20
-//zz fd =3D open("/proc/self/maps", O_RDONLY);
-//zz=20
-//zz if (fd =3D=3D -1) {
-//zz perror("open /proc/self/maps");
-//zz return;
-//zz }
-//zz=20
-//zz ret =3D read(fd, buf, sizeof(buf));
-//zz=20
-//zz if (ret =3D=3D -1) {
-//zz perror("read /proc/self/maps");
-//zz close(fd);
-//zz return;
-//zz }
-//zz close(fd);
-//zz=20
-//zz if (ret =3D=3D sizeof(buf)) {
-//zz VG_(printf)("coregrind/m_ume.c: buf too small\n");
-//zz return;
-//zz }
-//zz=20
-//zz while(bufptr && bufptr < buf+ret) {
-//zz char perm[5];
-//zz ULong offset;
-//zz int maj, min;
-//zz int ino;
-//zz void *segstart, *segend;
-//zz=20
-//zz sscanf(bufptr, "%p-%p %s %llx %x:%x %d",
-//zz &segstart, &segend, perm, &offset, &maj, &min, &ino);
-//zz bufptr =3D strchr(bufptr, '\n');
-//zz if (bufptr !=3D NULL)
-//zz bufptr++; /* skip \n */
-//zz=20
-//zz if (!(*fn)(segstart, segend, perm, offset, maj, min, ino, ext=
ra))
-//zz break;
-//zz }
-//zz }
-//zz=20
-//zz /*------------------------------------------------------------*/
-//zz /*--- Stack switching ---*/
-//zz /*------------------------------------------------------------*/
-//zz=20
-//zz // __attribute__((noreturn))
-//zz // void VG_(jump_and_switch_stacks) ( Addr stack, Addr dst );
-//zz #if defined(VGA_x86)
-//zz // 4(%esp) =3D=3D stack
-//zz // 8(%esp) =3D=3D dst
-//zz asm(
-//zz ".global vgPlain_jump_and_switch_stacks\n"
-//zz "vgPlain_jump_and_switch_stacks:\n"
-//zz " movl %esp, %esi\n" // remember old stack pointer
-//zz " movl 4(%esi), %esp\n" // set stack
-//zz " pushl 8(%esi)\n" // dst to stack
-//zz " movl $0, %eax\n" // zero all GP regs
-//zz " movl $0, %ebx\n"
-//zz " movl $0, %ecx\n"
-//zz " movl $0, %edx\n"
-//zz " movl $0, %esi\n"
-//zz " movl $0, %edi\n"
-//zz " movl $0, %ebp\n"
-//zz " ret\n" // jump to dst
-//zz " ud2\n" // should never get here
-//zz );
-//zz #elif defined(VGA_amd64)
-//zz // %rdi =3D=3D stack
-//zz // %rsi =3D=3D dst
-//zz asm(
-//zz ".global vgPlain_jump_and_switch_stacks\n"
-//zz "vgPlain_jump_and_switch_stacks:\n"
-//zz " movq %rdi, %rsp\n" // set stack
-//zz " pushq %rsi\n" // dst to stack
-//zz " movq $0, %rax\n" // zero all GP regs
-//zz " movq $0, %rbx\n"
-//zz " movq $0, %rcx\n"
-//zz " movq $0, %rdx\n"
-//zz " movq $0, %rsi\n"
-//zz " movq $0, %rdi\n"
-//zz " movq $0, %rbp\n"
-//zz " movq $0, %r8\n"
-//zz " movq $0, %r9\n"
-//zz " movq $0, %r10\n"
-//zz " movq $0, %r11\n"
-//zz " movq $0, %r12\n"
-//zz " movq $0, %r13\n"
-//zz " movq $0, %r14\n"
-//zz " movq $0, %r15\n"
-//zz " ret\n" // jump to dst
-//zz " ud2\n" // should never get here
-//zz );
-//zz=20
-//zz #elif defined(VGA_ppc32)
-//zz /* Jump to 'dst', but first set the stack pointer to 'stack'. Also=
,
-//zz clear all the integer registers before entering 'dst'. It's
-//zz important that the stack pointer is set to exactly 'stack' and n=
ot
-//zz (eg) stack - apparently_harmless_looking_small_offset. Basicall=
y
-//zz because the code at 'dst' might be wanting to scan the area abov=
e
-//zz 'stack' (viz, the auxv array), and putting spurious words on the
-//zz stack confuses it.
-//zz */
-//zz // %r3 =3D=3D stack
-//zz // %r4 =3D=3D dst
-//zz asm(
-//zz ".global vgPlain_jump_and_switch_stacks\n"
-//zz "vgPlain_jump_and_switch_stacks:\n"
-//zz " mtctr %r4\n\t" // dst to %ctr
-//zz " mr %r1,%r3\n\t" // stack to %sp
-//zz " li 0,0\n\t" // zero all GP regs
-//zz " li 3,0\n\t"
-//zz " li 4,0\n\t"
-//zz " li 5,0\n\t"
-//zz " li 6,0\n\t"
-//zz " li 7,0\n\t"
-//zz " li 8,0\n\t"
-//zz " li 9,0\n\t"
-//zz " li 10,0\n\t"
-//zz " li 11,0\n\t"
-//zz " li 12,0\n\t"
-//zz " li 13,0\n\t" // CAB: This right? r13 =3D small data a=
rea ptr
-//zz " li 14,0\n\t"
-//zz " li 15,0\n\t"
-//zz " li 16,0\n\t"
-//zz " li 17,0\n\t"
-//zz " li 18,0\n\t"
-//zz " li 19,0\n\t"
-//zz " li 20,0\n\t"
-//zz " li 21,0\n\t"
-//zz " li 22,0\n\t"
-//zz " li 23,0\n\t"
-//zz " li 24,0\n\t"
-//zz " li 25,0\n\t"
-//zz " li 26,0\n\t"
-//zz " li 27,0\n\t"
-//zz " li 28,0\n\t"
-//zz " li 29,0\n\t"
-//zz " li 30,0\n\t"
-//zz " li 31,0\n\t"
-//zz " mtxer 0\n\t"
-//zz " mtcr 0\n\t"
-//zz " mtlr %r0\n\t"
-//zz " bctr\n\t" // jump to dst
-//zz " trap\n" // should never get here
-//zz );
-//zz=20
-//zz #else
-//zz # error Unknown architecture
-//zz #endif
-
/*------------------------------------------------------------*/
/*--- Finding auxv on the stack ---*/
/*------------------------------------------------------------*/
@@ -267,11 +108,11 @@
/*------------------------------------------------------------*/
=20
static=20
-struct elfinfo *readelf(int fd, const char *filename)
+struct elfinfo *readelf(Int fd, const char *filename)
{
SysRes sres;
struct elfinfo *e =3D VG_(malloc)(sizeof(*e));
- int phsz;
+ Int phsz;
=20
vg_assert(e);
e->fd =3D fd;
@@ -424,11 +265,7 @@
return elfbrk;
}
=20
-// Forward declaration.
-/* returns: 0 =3D success, non-0 is failure */
-static int do_exec_inner(const char *exe, struct exeinfo *info);
-
-static int match_ELF(const char *hdr, int len)
+static Bool match_ELF(const char *hdr, Int len)
{
ESZ(Ehdr) *e =3D (ESZ(Ehdr) *)hdr;
return (len > sizeof(*e)) && VG_(memcmp)(&e->e_ident[0], ELFMAG, SELF=
MAG) =3D=3D 0;
@@ -478,8 +315,7 @@
=20
- The entry point in INFO is set to the interpreter's entry point,
and we're done. */
-static int load_ELF(char *hdr, int len, int fd, const char *name,
- /*MOD*/struct exeinfo *info)
+static Int load_ELF(Int fd, const char *name, /*MOD*/struct exeinfo *inf=
o)
{
SysRes sres;
struct elfinfo *e;
@@ -489,7 +325,7 @@
ESZ(Addr) interp_addr =3D 0; /* interpreter (ld.so) address */
ESZ(Word) interp_size =3D 0; /* interpreter size */
ESZ(Word) interp_align =3D VKI_PAGE_SIZE;
- int i;
+ Int i;
void *entry;
ESZ(Addr) ebase =3D 0;
=20
@@ -529,9 +365,9 @@
=09
case PT_INTERP: {
char *buf =3D VG_(malloc)(ph->p_filesz+1);
- int j;
- int intfd;
- int baseaddr_set;
+ Int j;
+ Int intfd;
+ Int baseaddr_set;
=20
vg_assert(buf);
VG_(pread)(fd, buf, ph->p_filesz, ph->p_offset);
@@ -646,30 +482,63 @@
}
=20
=20
-static int match_script(const char *hdr, Int len)
+static Bool match_script(char *hdr, Int len)
{
- return (len > 2) && VG_(memcmp)(hdr, "#!", 2) =3D=3D 0;
+ Char* end =3D hdr + len;
+ Char* interp =3D hdr + 2;
+
+ // len < 4: need '#', '!', plus at least a '/' and one more char
+ if (len < 4) return False; =20
+ if (0 !=3D VG_(memcmp)(hdr, "#!", 2)) return False;
+
+ // Find interpreter name, make sure it's an absolute path (starts wit=
h
+ // '/') and has at least one more char.
+ while (interp < end && VG_(isspace)(*interp)) interp++;
+ if (*interp !=3D '/') return False; // absolute path only for inter=
preter
+ if (interp =3D=3D end) return False; // nothing after the '/'
+
+ // Here we should get the full interpreter name and check it with
+ // check_executable(). See the "EXEC FAILED" failure when running sh=
ell
+ // for an example.
+
+ return True; // looks like a #! script
}
=20
+// Forward declaration.
+static Int do_exec_inner(const char *exe, struct exeinfo *info);
+
/* returns: 0 =3D success, non-0 is failure */
-static int load_script(char *hdr, int len, int fd, const char *name,
- struct exeinfo *info)
+static Int load_script(Int fd, const char *name, struct exeinfo *info)
{
- char *interp;
- char *const end =3D hdr+len;
- char *cp;
- char *arg =3D NULL;
- int eol;
+ Char hdr[VKI_PAGE_SIZE];
+ Int len =3D VKI_PAGE_SIZE;
+ Int eol;
+ Char* interp;
+ Char* end;
+ Char* cp;
+ Char* arg =3D NULL;
+ SysRes res;
=20
+ // Read the first part of the file.
+ res =3D VG_(pread)(fd, hdr, len, 0);
+ if (res.isError) {
+ VG_(close)(fd);
+ return VKI_EACCES;
+ } else {
+ len =3D res.val;
+ }
+
+ vg_assert('#' =3D=3D hdr[0] && '!' =3D=3D hdr[1]);
+
+ end =3D hdr + len;
interp =3D hdr + 2;
- while(interp < end && (*interp =3D=3D ' ' || *interp =3D=3D '\t'))
+ while (interp < end && VG_(isspace)(*interp))
interp++;
=20
- if (*interp !=3D '/')
- return VKI_ENOEXEC; /* absolute path only for interpreter */
+ vg_assert(*interp =3D=3D '/'); /* absolute path only for interprete=
r */
=20
/* skip over interpreter name */
- for(cp =3D interp; cp < end && *cp !=3D ' ' && *cp !=3D '\t' && *cp !=
=3D '\n'; cp++)
+ for (cp =3D interp; cp < end && !VG_(isspace)(*cp); cp++)
;
=20
eol =3D (*cp =3D=3D '\n');
@@ -678,7 +547,7 @@
=20
if (!eol && cp < end) {
/* skip space before arg */
- while (cp < end && (*cp =3D=3D '\t' || *cp =3D=3D ' '))
+ while (cp < end && VG_(isspace)(*cp))
cp++;
=20
/* arg is from here to eol */
@@ -705,130 +574,215 @@
return do_exec_inner(interp, info);
}
=20
-/*=20
- Emulate the normal Unix permissions checking algorithm.
=20
- If owner matches, then use the owner permissions, else
- if group matches, then use the group permissions, else
- use other permissions.
+typedef enum {
+ VG_EXE_FORMAT_ELF =3D 1,
+ VG_EXE_FORMAT_SCRIPT =3D 2,
+} ExeFormat;
=20
- Note that we can't deal with SUID/SGID, so we refuse to run them
- (otherwise the executable may misbehave if it doesn't have the
- permissions it thinks it does).
-*/
-/* returns: 0 =3D success, non-0 is failure */
-static int check_perms(int fd)
+// Check the file looks executable.
+SysRes VG_(pre_exec_check)(const Char* exe_name, Int* out_fd)
{
- struct vki_stat st;
+ Int fd, ret;
+ SysRes res;
+ Char buf[VKI_PAGE_SIZE];
+ SizeT bufsz =3D VKI_PAGE_SIZE, fsz;
=20
- if (VG_(fstat)(fd, &st) =3D=3D -1)=20
- return VKI_EACCES;
+ // Check it's readable
+ res =3D VG_(open)(exe_name, VKI_O_RDONLY, 0);
+ if (res.isError) {
+ return res;
+ }
+ fd =3D res.val;
=20
- if (st.st_mode & (VKI_S_ISUID | VKI_S_ISGID)) {
- //VG_(printf)("Can't execute suid/sgid executable %s\n", exe);
- return VKI_EACCES;
+ // Check we have execute permissions
+ ret =3D VG_(check_executable)((HChar*)exe_name);
+ if (0 !=3D ret) {
+ VG_(close)(fd);
+ return VG_(mk_SysRes_Error)(ret);
}
=20
- if (VG_(geteuid)() =3D=3D st.st_uid) {
- if (!(st.st_mode & VKI_S_IXUSR))
- return VKI_EACCES;
- } else {
- int grpmatch =3D 0;
+ fsz =3D VG_(fsize)(fd);
+ if (fsz < bufsz)
+ bufsz =3D fsz;
=20
- if (VG_(getegid)() =3D=3D st.st_gid)
- grpmatch =3D 1;
- else {
- UInt groups[32];
- Int ngrp =3D VG_(getgroups)(32, groups);
- Int i;
- /* ngrp will be -1 if VG_(getgroups) failed. */
- for (i =3D 0; i < ngrp; i++) {
- if (groups[i] =3D=3D st.st_gid) {
- grpmatch =3D 1;
- break;
- }
- }
- }
+ res =3D VG_(pread)(fd, buf, bufsz, 0);
+ if (res.isError || res.val !=3D bufsz) {
+ VG_(close)(fd);
+ return VG_(mk_SysRes_Error)(VKI_EACCES);
+ }
+ bufsz =3D res.val;
=20
- if (grpmatch) {
- if (!(st.st_mode & VKI_S_IXGRP))
- return VKI_EACCES;
- } else if (!(st.st_mode & VKI_S_IXOTH))
- return VKI_EACCES;
+ if (match_ELF(buf, bufsz)) {
+ res =3D VG_(mk_SysRes_Success)(VG_EXE_FORMAT_ELF);
+ } else if (match_script(buf, bufsz)) {
+ res =3D VG_(mk_SysRes_Success)(VG_EXE_FORMAT_SCRIPT);
+ } else {
+ res =3D VG_(mk_SysRes_Error)(VKI_ENOEXEC);
}
=20
- return 0;
+ // Write the 'out_fd' param if necessary, or close the file.
+ if (!res.isError && out_fd) {
+ *out_fd =3D fd;=20
+ } else {=20
+ VG_(close)(fd);
+ }
+
+ return res;
}
=20
-/* returns: 0 =3D success, non-0 is failure */
-static int do_exec_inner(const char *exe, struct exeinfo *info)
+// returns: 0 =3D success, non-0 is failure
+//
+// We can execute only ELF binaries or scripts that begin with "#!". (N=
ot,
+// for example, scripts that don't begin with "#!"; see the VG_(do_exec=
)()
+// invocation from m_main.c for how that's handled.)
+static Int do_exec_inner(const char *exe, struct exeinfo *info)
{
- SysRes sres;
- int fd;
- int err;
- char buf[VKI_PAGE_SIZE];
- int bufsz;
- int i;
- int ret;
- static const struct {
- int (*match)(const char *hdr, int len);
- int (*load) ( char *hdr, int len, int fd2, const char *name,
- struct exeinfo *);
- } formats[] =3D {
- { match_ELF, load_ELF },
- { match_script, load_script },
- };
+ SysRes res;
+ Int fd;
+ Int ret;
=20
- sres =3D VG_(open)(exe, VKI_O_RDONLY, 0);
- if (sres.isError) {
- if (0)
- VG_(printf)("Can't open executable %s: %s\n",
- exe, VG_(strerror)(sres.val));
- return sres.val;
- }
- fd =3D sres.val;
+ res =3D VG_(pre_exec_check)(exe, &fd);
+ if (res.isError)
+ return res.val;
=20
- err =3D check_perms(fd);
- if (err !=3D 0) {
- VG_(close)(fd);
- return err;
+ switch (res.val) {
+ case VG_EXE_FORMAT_ELF: ret =3D load_ELF (fd, exe, info); break=
;
+ case VG_EXE_FORMAT_SCRIPT: ret =3D load_script(fd, exe, info); break=
;
+ default:
+ vg_assert2(0, "unrecognised VG_EXE_FORMAT value\n");
}
=20
- bufsz =3D VG_(fsize)(fd);
- if (bufsz > sizeof(buf))
- bufsz =3D sizeof(buf);
+ VG_(close)(fd);
=20
- sres =3D VG_(pread)(fd, buf, bufsz, 0);
- if (sres.isError || sres.val !=3D bufsz) {
- VG_(printf)("Can't read executable header: %s\n",
- VG_(strerror)(sres.val));
- VG_(close)(fd);
- return sres.val;
+ return ret;
+}
+
+
+static Bool is_hash_bang_file(Char* f)
+{
+ SysRes res =3D VG_(open)(f, VKI_O_RDONLY, 0);
+ if (!res.isError) {
+ Char buf[3] =3D {0,0,0};
+ Int fd =3D res.val;
+ Int n =3D VG_(read)(fd, buf, 2);=20
+ if (n =3D=3D 2 && VG_STREQ("#!", buf))
+ return True;
}
- bufsz =3D sres.val;
+ return False;
+}
=20
- ret =3D VKI_ENOEXEC;
- for(i =3D 0; i < sizeof(formats)/sizeof(*formats); i++) {
- if ((formats[i].match)(buf, bufsz)) {
- ret =3D (formats[i].load)(buf, bufsz, fd, exe, info);
- break;
+// Look at the first 80 chars, and if any are greater than 127, it's bin=
ary.
+// This is crude, but should be good enough. Note that it fails on a
+// zero-length file, as we want.
+static Bool is_binary_file(Char* f)
+{
+ SysRes res =3D VG_(open)(f, VKI_O_RDONLY, 0);
+ if (!res.isError) {
+ UChar buf[80];
+ Int fd =3D res.val;
+ Int n =3D VG_(read)(fd, buf, 80);=20
+ Int i;
+ for (i =3D 0; i < n; i++) {
+ if (buf[i] > 127)
+ return True; // binary char found
}
+ return False;
+ } else {
+ // Something went wrong. This will only happen if we earlier
+ // succeeded in opening the file but fail here (eg. the file was
+ // deleted between then and now).
+ VG_(printf)("valgrind: %s: unknown error\n", f);
+ VG_(exit)(126); // 126 =3D=3D NOEXEC
}
+}
=20
- VG_(close)(fd);
+// If the do_exec fails we try to emulate what the shell does (I used
+// bash as a guide). It's worth noting that the shell can execute some
+// things that VG_(do_exec)() (which subsitutes for the kernel's exec())
+// will refuse to (eg. scripts lacking a "#!" prefix).
+static Int do_exec_shell_followup(Int ret, Char* exe_name,
+ struct exeinfo* info)
+{
+ Char* default_interp_name =3D "/bin/sh";
+ SysRes res;
+ struct vki_stat st;
=20
+ if (VKI_ENOEXEC =3D=3D ret) {
+ // It was an executable file, but in an unacceptable format. Prob=
ably
+ // is a shell script lacking the "#!" prefix; try to execute it s=
o.
+
+ // Is it a binary file? =20
+ if (is_binary_file(exe_name)) {
+ VG_(printf)("valgrind: %s: cannot execute binary file\n", exe_n=
ame);
+ VG_(exit)(126); // 126 =3D=3D NOEXEC
+ }
+
+ // Looks like a script. Run it with /bin/sh. This includes
+ // zero-length files.
+
+ info->interp_name =3D VG_(strdup)(default_interp_name);
+ info->interp_args =3D NULL;
+ if (info->argv && info->argv[0] !=3D NULL)
+ info->argv[0] =3D (char *)exe_name;
+
+ ret =3D do_exec_inner(info->interp_name, info);
+
+ if (0 !=3D ret) {
+ // Something went wrong with executing the default interpreter
+ VG_(printf)("valgrind: %s: bad interpreter (%s): %s\n",
+ exe_name, info->interp_name, VG_(strerror)(ret));
+ VG_(exit)(126); // 126 =3D=3D NOEXEC
+ }
+
+ } else if (0 !=3D ret) {
+ // Something else went wrong. Try to make the error more specific=
,
+ // and then print a message and abort.
+ =20
+ // Was it a directory?
+ res =3D VG_(stat)(exe_name, &st);
+ if (!res.isError && VKI_S_ISDIR(st.st_mode)) {
+ VG_(printf)("valgrind: %s: is a directory\n", exe_name);
+ =20
+ // Was it not executable?
+ } else if (0 !=3D VG_(check_executable)(exe_name)) {
+ VG_(printf)("valgrind: %s: %s\n", exe_name, VG_(strerror)(ret))=
;
+
+ // Did it start with "#!"? If so, it must have been a bad interpr=
eter.
+ } else if (is_hash_bang_file(exe_name)) {
+ VG_(printf)("valgrind: %s: bad interpreter: %s\n",
+ exe_name, VG_(strerror)(ret));
+
+ // Otherwise it was something else.
+ } else {
+ VG_(printf)("valgrind: %s\n", exe_name, VG_(strerror)(ret));
+ }
+ // 126 means NOEXEC; I think this is Posix, and that in some case=
s we
+ // should be returning 127, meaning NOTFOUND. Oh well.
+ VG_(exit)(126);
+ }
return ret;
}
=20
+
+// This emulates the kernel's exec(). If it fails, it then emulates the
+// shell's handling of the situation.
// See ume.h for an indication of which entries of 'info' are inputs, wh=
ich
// are outputs, and which are both.
/* returns: 0 =3D success, non-0 is failure */
-int VG_(do_exec)(const char *exe, struct exeinfo *info)
+Int VG_(do_exec)(const char *exe_name, struct exeinfo *info)
{
+ Int ret;
+ =20
info->interp_name =3D NULL;
info->interp_args =3D NULL;
=20
- return do_exec_inner(exe, info);
+ ret =3D do_exec_inner(exe_name, info);
+
+ if (0 !=3D ret) {
+ ret =3D do_exec_shell_followup(ret, (Char*)exe_name, info);
+ }
+ return ret;
}
=20
/*--------------------------------------------------------------------*/
Modified: trunk/coregrind/pub_core_libcfile.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/pub_core_libcfile.h 2005-10-13 15:54:20 UTC (rev 4917=
)
+++ trunk/coregrind/pub_core_libcfile.h 2005-10-14 03:11:30 UTC (rev 4918=
)
@@ -48,6 +48,9 @@
/* Return the size of a file */
extern Int VG_(fsize) ( Int fd );
=20
+/* Is the file a directory? */
+extern Bool VG_(is_dir) ( HChar* f );
+
/* Default destination port to be used in logging over a network, if
none specified. */
#define VG_CLO_DEFAULT_LOGPORT 1500
@@ -61,6 +64,9 @@
=20
extern Int VG_(access) ( HChar* path, Bool irusr, Bool iwusr, Bool ixusr=
);
=20
+/* Is the file executable? Returns: 0 =3D success, non-0 is failure */
+extern Int VG_(check_executable)(HChar* f);
+
extern SysRes VG_(pread) ( Int fd, void* buf, Int count, Int offset );
=20
/* Create and open (-rw------) a tmp file name incorporating said arg.
Modified: trunk/coregrind/pub_core_ume.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/pub_core_ume.h 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/coregrind/pub_core_ume.h 2005-10-14 03:11:30 UTC (rev 4918)
@@ -93,11 +93,17 @@
char* interp_args; // OUT: the args for the interpreter
};
=20
+// Do a number of appropriate checks to see if the file looks executable=
by
+// the kernel: ie. it's a file, it's readable and executable, and it's i=
n
+// either ELF or "#!" format. On success, 'out_fd' gets the fd of the f=
ile
+// if it's non-NULL. Otherwise the fd is closed.
+extern SysRes VG_(pre_exec_check)(const Char* exe_name, Int* out_fd);
+
// Does everything short of actually running 'exe': finds the file,
// checks execute permissions, sets up interpreter if program is a scrip=
t,=20
// reads headers, maps file into memory, and returns important info abou=
t
// the program.
-extern int VG_(do_exec)(const char *exe, struct exeinfo *info);
+extern Int VG_(do_exec)(const char *exe, struct exeinfo *info);
=20
/*------------------------------------------------------------*/
/*--- Finding and dealing with auxv ---*/
Modified: trunk/none/tests/Makefile.am
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/Makefile.am 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/none/tests/Makefile.am 2005-10-14 03:11:30 UTC (rev 4918)
@@ -84,6 +84,17 @@
selfrun.stderr.exp selfrun.stdout.exp selfrun.vgtest \
sem.stderr.exp sem.stdout.exp sem.vgtest \
semlimit.stderr.exp semlimit.stdout.exp semlimit.vgtest \
+ shell shell.vgtest shell.stderr.exp shell.stdout.exp \
+ shell_badinterp shell_badinterp.vgtest shell_badinterp.stderr.exp \
+ shell_binaryfile shell_binaryfile.vgtest shell_binaryfile.stderr.exp \
+ shell_dir.vgtest shell_dir.stderr.exp \
+ shell_nonexec shell_nonexec.vgtest shell_nonexec.stderr.exp \
+ shell_nonexec shell_nonexec.vgtest shell_nonexec.stderr.exp \
+ shell_nosuchfile.vgtest shell_nosuchfile.stderr.exp \
+ shell_valid1 shell_valid1.vgtest shell_valid1.stderr.exp \
+ shell_valid2 shell_valid2.vgtest shell_valid2.stderr.exp \
+ shell_valid3 shell_valid3.vgtest shell_valid3.stderr.exp \
+ shell_zerolength shell_zerolength.vgtest shell_zerolength.stderr.exp \
susphello.stdout.exp susphello.stderr.exp susphello.vgtest \
sha1_test.stderr.exp sha1_test.vgtest \
shortpush.stderr.exp shortpush.vgtest \
Modified: trunk/none/tests/cmdline5.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/cmdline5.stderr.exp 2005-10-13 15:54:20 UTC (rev 491=
7)
+++ trunk/none/tests/cmdline5.stderr.exp 2005-10-14 03:11:30 UTC (rev 491=
8)
@@ -1 +1 @@
-valgrind: do_exec(./no-such-program-my-friend) failed: No such file or d=
irectory
+valgrind: ./no-such-program-my-friend: No such file or directory
Modified: trunk/none/tests/cmdline6.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/cmdline6.stderr.exp 2005-10-13 15:54:20 UTC (rev 491=
7)
+++ trunk/none/tests/cmdline6.stderr.exp 2005-10-14 03:11:30 UTC (rev 491=
8)
@@ -1 +1 @@
-valgrind: do_exec(./cmdline6.vgtest) failed: Permission denied
+valgrind: ./cmdline6.vgtest: Permission denied
Added: trunk/none/tests/shell
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/none/tests/shell 2005-10-14 03:11:30 UTC (rev 4918)
@@ -0,0 +1,41 @@
+#! /bin/sh
+#
+# Testing various shell script invocations.
+
+#-----------------------------------------------------------------------=
-----
+# Shell scripts that should fail
+#-----------------------------------------------------------------------=
-----
+
+echo "Execute a directory"
+x86/
+
+echo "Execute a directory (2)"
+x86
+
+echo "Execute a non-executable file"
+shell.vgtest
+
+echo "Execute a script with a bad interpreter name"
+shell_badinterp
+
+echo "Execute a binary file"
+shell_binaryfile
+
+echo "Execute a non-existent file"
+shell_nosuchfile
+
+#-----------------------------------------------------------------------=
-----
+# Shell scripts that should pass
+#-----------------------------------------------------------------------=
-----
+echo "Execute a valid script with a #! line"
+shell_valid1
+
+echo "Execute a valid script without a #! line"
+shell_valid2
+
+echo "Execute a valid script with #! but no interpname"
+shell_valid3
+
+echo "Execute a zero-length file"
+shell_zerolength
+
Property changes on: trunk/none/tests/shell
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/none/tests/shell.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell.stderr.exp 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/none/tests/shell.stderr.exp 2005-10-14 03:11:30 UTC (rev 4918)
@@ -0,0 +1,18 @@
+
+./shell: x86/: is a directory
+
+./shell: x86: command not found
+
+./shell: ./shell.vgtest: Permission denied
+
+execve(0x........(./shell_badinterp), 0x........, 0x........) failed, er=
rno 2
+EXEC FAILED: I can't recover from execve() failing, so I'm dying.
+Add more stringent tests in PRE(sys_execve), or work out how to recover.
+./shell: ./shell_binaryfile: cannot execute binary file
+
+./shell: shell_nosuchfile: command not found
+
+
+
+
+
Added: trunk/none/tests/shell.stdout.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell.stdout.exp 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/none/tests/shell.stdout.exp 2005-10-14 03:11:30 UTC (rev 4918)
@@ -0,0 +1,10 @@
+Execute a directory
+Execute a directory (2)
+Execute a non-executable file
+Execute a script with a bad interpreter name
+Execute a binary file
+Execute a non-existent file
+Execute a valid script with a #! line
+Execute a valid script without a #! line
+Execute a valid script with #! but no interpname
+Execute a zero-length file
Added: trunk/none/tests/shell.vgtest
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell.vgtest 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/none/tests/shell.vgtest 2005-10-14 03:11:30 UTC (rev 4918)
@@ -0,0 +1 @@
+prog: shell
Added: trunk/none/tests/shell_badinterp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_badinterp 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/none/tests/shell_badinterp 2005-10-14 03:11:30 UTC (rev 4918)
@@ -0,0 +1,3 @@
+#! /this/is/a/bogus/interpreter/name
+
+true
Property changes on: trunk/none/tests/shell_badinterp
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/none/tests/shell_badinterp.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_badinterp.stderr.exp 2005-10-13 15:54:20 UTC (=
rev 4917)
+++ trunk/none/tests/shell_badinterp.stderr.exp 2005-10-14 03:11:30 UTC (=
rev 4918)
@@ -0,0 +1 @@
+valgrind: ./shell_badinterp: bad interpreter: No such file or directory
Added: trunk/none/tests/shell_badinterp.vgtest
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_badinterp.vgtest 2005-10-13 15:54:20 UTC (rev =
4917)
+++ trunk/none/tests/shell_badinterp.vgtest 2005-10-14 03:11:30 UTC (rev =
4918)
@@ -0,0 +1 @@
+prog: shell_badinterp
Added: trunk/none/tests/shell_binaryfile
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
(Binary files differ)
Property changes on: trunk/none/tests/shell_binaryfile
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ application/octet-stream
Added: trunk/none/tests/shell_binaryfile.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_binaryfile.stderr.exp 2005-10-13 15:54:20 UTC =
(rev 4917)
+++ trunk/none/tests/shell_binaryfile.stderr.exp 2005-10-14 03:11:30 UTC =
(rev 4918)
@@ -0,0 +1 @@
+valgrind: ./shell_binaryfile: cannot execute binary file
Added: trunk/none/tests/shell_binaryfile.vgtest
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_binaryfile.vgtest 2005-10-13 15:54:20 UTC (rev=
4917)
+++ trunk/none/tests/shell_binaryfile.vgtest 2005-10-14 03:11:30 UTC (rev=
4918)
@@ -0,0 +1 @@
+prog: shell_binaryfile
Added: trunk/none/tests/shell_dir.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_dir.stderr.exp 2005-10-13 15:54:20 UTC (rev 49=
17)
+++ trunk/none/tests/shell_dir.stderr.exp 2005-10-14 03:11:30 UTC (rev 49=
18)
@@ -0,0 +1 @@
+valgrind: ./x86/: is a directory
Added: trunk/none/tests/shell_dir.vgtest
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_dir.vgtest 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/none/tests/shell_dir.vgtest 2005-10-14 03:11:30 UTC (rev 4918)
@@ -0,0 +1 @@
+prog: x86/
Added: trunk/none/tests/shell_nonexec.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_nonexec.stderr.exp 2005-10-13 15:54:20 UTC (re=
v 4917)
+++ trunk/none/tests/shell_nonexec.stderr.exp 2005-10-14 03:11:30 UTC (re=
v 4918)
@@ -0,0 +1 @@
+valgrind: ./shell.vgtest: Permission denied
Added: trunk/none/tests/shell_nonexec.vgtest
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_nonexec.vgtest 2005-10-13 15:54:20 UTC (rev 49=
17)
+++ trunk/none/tests/shell_nonexec.vgtest 2005-10-14 03:11:30 UTC (rev 49=
18)
@@ -0,0 +1 @@
+prog: shell.vgtest
Added: trunk/none/tests/shell_nosuchfile.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_nosuchfile.stderr.exp 2005-10-13 15:54:20 UTC =
(rev 4917)
+++ trunk/none/tests/shell_nosuchfile.stderr.exp 2005-10-14 03:11:30 UTC =
(rev 4918)
@@ -0,0 +1 @@
+valgrind: ./shell_nosuchfile: No such file or directory
Added: trunk/none/tests/shell_nosuchfile.vgtest
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_nosuchfile.vgtest 2005-10-13 15:54:20 UTC (rev=
4917)
+++ trunk/none/tests/shell_nosuchfile.vgtest 2005-10-14 03:11:30 UTC (rev=
4918)
@@ -0,0 +1 @@
+prog: shell_nosuchfile
Added: trunk/none/tests/shell_valid1
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_valid1 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/none/tests/shell_valid1 2005-10-14 03:11:30 UTC (rev 4918)
@@ -0,0 +1,5 @@
+#! /bin/sh
+#
+# This is a valid script with a #! line
+
+true
Property changes on: trunk/none/tests/shell_valid1
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/none/tests/shell_valid1.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Added: trunk/none/tests/shell_valid1.vgtest
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_valid1.vgtest 2005-10-13 15:54:20 UTC (rev 491=
7)
+++ trunk/none/tests/shell_valid1.vgtest 2005-10-14 03:11:30 UTC (rev 491=
8)
@@ -0,0 +1,2 @@
+prog: shell_valid1
+vgopts: -q
Added: trunk/none/tests/shell_valid2
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_valid2 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/none/tests/shell_valid2 2005-10-14 03:11:30 UTC (rev 4918)
@@ -0,0 +1,6 @@
+#
+#
+# This is a valid script without a #! line=20
+
+true
+
Property changes on: trunk/none/tests/shell_valid2
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/none/tests/shell_valid2.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Added: trunk/none/tests/shell_valid2.vgtest
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_valid2.vgtest 2005-10-13 15:54:20 UTC (rev 491=
7)
+++ trunk/none/tests/shell_valid2.vgtest 2005-10-14 03:11:30 UTC (rev 491=
8)
@@ -0,0 +1,2 @@
+prog: shell_valid1
+vgopts: -q
Added: trunk/none/tests/shell_valid3
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_valid3 2005-10-13 15:54:20 UTC (rev 4917)
+++ trunk/none/tests/shell_valid3 2005-10-14 03:11:30 UTC (rev 4918)
@@ -0,0 +1,5 @@
+#! =20
+#
+# The interpreter name is missing in this file.
+
+true
Property changes on: trunk/none/tests/shell_valid3
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/none/tests/shell_valid3.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Added: trunk/none/tests/shell_valid3.vgtest
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_valid3.vgtest 2005-10-13 15:54:20 UTC (rev 491=
7)
+++ trunk/none/tests/shell_valid3.vgtest 2005-10-14 03:11:30 UTC (rev 491=
8)
@@ -0,0 +1,2 @@
+prog: shell_valid1
+vgopts: -q
Added: trunk/none/tests/shell_zerolength
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Property changes on: trunk/none/tests/shell_zerolength
___________________________________________________________________
Name: svn:executable
+ *
Added: trunk/none/tests/shell_zerolength.stderr.exp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Added: trunk/none/tests/shell_zerolength.vgtest
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/none/tests/shell_zerolength.vgtest 2005-10-13 15:54:20 UTC (rev=
4917)
+++ trunk/none/tests/shell_zerolength.vgtest 2005-10-14 03:11:30 UTC (rev=
4918)
@@ -0,0 +1,2 @@
+prog: shell_zerolength
+vgopts: -q
|
|
From: Oswald B. <os...@kd...> - 2005-10-14 06:06:38
|
On Fri, Oct 14, 2005 at 04:11:31AM +0100, sv...@va... wrote:
> Author: njn
> +Int VG_(check_executable)(HChar* f)
> +{
> + struct vki_stat st;
> + SysRes res;
> +
> + res = VG_(stat)(f, &st);
>
its not really relevant for valgrind (as it does not run with elevated
privileges), but in such cases one should use fstat() - otherwise there
is a race condition which is exploitable with a symlink attack.
> + if (st.st_mode & (VKI_S_ISUID | VKI_S_ISGID)) {
> + //VG_(printf)("Can't execute suid/sgid executable %s\n", exe);
> + return VKI_EACCES;
> + }
> +
i would not outright refuse anything suid/sgid, but also check whether
the bits would take effect in a particular case (e[ug]id != st.st_[ug]id).
> + if (VG_(geteuid)() == st.st_uid) {
> + if (!(st.st_mode & VKI_S_IXUSR))
> + return VKI_EACCES;
> + } else {
> [...]
>
given that it does not matter whether we use uid or euid (last time i
checked, valgrind was not suid/sgid :), and that the above mentioned
race is probably not relevant (also because it's not suid/sgid), how
about simply using access(f, X_OK)?
--
Hi! I'm a .signature virus! Copy me into your ~/.signature, please!
--
Chaos, panic, and disorder - my work here is done.
|