| diff --git a/config.h.in b/config.h.in |
| index a5ad9e7..62a6b32 100644 |
| |
| |
| @@ -748,6 +748,9 @@ |
| /* Define if you have the pselect function. */ |
| #undef HAVE_PSELECT |
| |
| +/* Define if you have the pread function. */ |
| +#undef HAVE_PREAD |
| + |
| /* Define if you have the putenv function. */ |
| #undef HAVE_PUTENV |
| |
| @@ -946,6 +949,9 @@ |
| /* Define if you have the <dlfcn.h> header file. */ |
| #undef HAVE_DLFCN_H |
| |
| +/* Define if you have the <elf.h> header file. */ |
| +#undef HAVE_ELF_H |
| + |
| /* Define if you have the <grp.h> header file. */ |
| #undef HAVE_GRP_H |
| |
| diff --git a/configure.ac b/configure.ac |
| index ce4e9b6..eda95d6 100644 |
| |
| |
| @@ -700,7 +700,7 @@ BASH_HEADER_INTTYPES |
| AC_CHECK_HEADERS(unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ |
| memory.h locale.h termcap.h termio.h termios.h dlfcn.h \ |
| stdbool.h stddef.h stdint.h netdb.h pwd.h grp.h strings.h \ |
| - regex.h syslog.h ulimit.h) |
| + regex.h syslog.h ulimit.h elf.h) |
| AC_CHECK_HEADERS(sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \ |
| sys/param.h sys/socket.h sys/stat.h \ |
| sys/time.h sys/times.h sys/types.h sys/wait.h) |
| @@ -771,7 +771,7 @@ dnl checks for system calls |
| AC_CHECK_FUNCS(dup2 eaccess fcntl getdtablesize getgroups gethostname \ |
| getpagesize getpeername getrlimit getrusage gettimeofday \ |
| kill killpg lstat pselect readlink sbrk select setdtablesize \ |
| - setitimer tcgetpgrp uname ulimit waitpid) |
| + setitimer tcgetpgrp uname ulimit waitpid pread) |
| AC_REPLACE_FUNCS(rename) |
| |
| dnl checks for c library functions |
| diff --git a/execute_cmd.c b/execute_cmd.c |
| index 2a3df6d..b5cd405 100644 |
| |
| |
| @@ -41,6 +41,10 @@ |
| # include <unistd.h> |
| #endif |
| |
| +#ifdef HAVE_ELF_H |
| +# include <elf.h> |
| +#endif |
| + |
| #include "posixtime.h" |
| |
| #if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE) |
| @@ -5486,6 +5490,14 @@ shell_execve (command, args, env) |
| { |
| /* The file has the execute bits set, but the kernel refuses to |
| run it for some reason. See why. */ |
| +#if defined (HAVE_HASH_BANG_EXEC) || defined (HAVE_ELF_H) |
| + int fd = open (command, O_RDONLY); |
| + |
| + if (fd >= 0) |
| + sample_len = read (fd, sample, sizeof (sample)); |
| + else |
| + sample_len = -1; |
| +#endif |
| #if defined (HAVE_HASH_BANG_EXEC) |
| READ_SAMPLE_BUF (command, sample, sample_len); |
| if (sample_len > 0) |
| @@ -5495,6 +5507,7 @@ shell_execve (command, args, env) |
| char *interp; |
| int ilen; |
| |
| + close (fd); |
| interp = getinterp (sample, sample_len, (int *)NULL); |
| ilen = strlen (interp); |
| errno = i; |
| @@ -5510,6 +5523,136 @@ shell_execve (command, args, env) |
| return (EX_NOEXEC); |
| } |
| #endif |
| +#if defined (HAVE_ELF_H) |
| + if (i == ENOENT |
| + && sample_len > EI_NIDENT |
| + && memcmp (sample, ELFMAG, SELFMAG) == 0) |
| + { |
| + off_t offset = -1; |
| + |
| + /* It is an ELF file. Now determine whether it is dynamically |
| + linked and if yes, get the offset of the interpreter |
| + string. */ |
| + if (sample[EI_CLASS] == ELFCLASS32 |
| + && sample_len > sizeof (Elf32_Ehdr)) |
| + { |
| + Elf32_Ehdr ehdr; |
| + Elf32_Phdr *phdr; |
| + int nphdr; |
| + |
| + /* We have to copy the data since the sample buffer |
| + might not be aligned correctly to be accessed as |
| + an Elf32_Ehdr struct. */ |
| + memcpy (&ehdr, sample, sizeof (Elf32_Ehdr)); |
| + |
| + nphdr = ehdr.e_phnum; |
| + phdr = (Elf32_Phdr *) malloc (nphdr * ehdr.e_phentsize); |
| + if (phdr != NULL) |
| + { |
| +#ifdef HAVE_PREAD |
| + sample_len = pread (fd, phdr, nphdr * ehdr.e_phentsize, |
| + ehdr.e_phoff); |
| +#else |
| + if (lseek (fd, ehdr.e_phoff, SEEK_SET) != -1) |
| + sample_len = read (fd, phdr, |
| + nphdr * ehdr.e_phentsize); |
| + else |
| + sample_len = -1; |
| +#endif |
| + if (sample_len == nphdr * ehdr.e_phentsize) |
| + while (nphdr-- > 0) |
| + if (phdr[nphdr].p_type == PT_INTERP) |
| + { |
| + offset = phdr[nphdr].p_offset; |
| + break; |
| + } |
| + free (phdr); |
| + } |
| + } |
| + else if (sample[EI_CLASS] == ELFCLASS64 |
| + && sample_len > sizeof (Elf64_Ehdr)) |
| + { |
| + Elf64_Ehdr ehdr; |
| + Elf64_Phdr *phdr; |
| + int nphdr; |
| + |
| + /* We have to copy the data since the sample buffer |
| + might not be aligned correctly to be accessed as |
| + an Elf64_Ehdr struct. */ |
| + memcpy (&ehdr, sample, sizeof (Elf64_Ehdr)); |
| + |
| + nphdr = ehdr.e_phnum; |
| + phdr = (Elf64_Phdr *) malloc (nphdr * ehdr.e_phentsize); |
| + if (phdr != NULL) |
| + { |
| +#ifdef HAVE_PREAD |
| + sample_len = pread (fd, phdr, nphdr * ehdr.e_phentsize, |
| + ehdr.e_phoff); |
| +#else |
| + if (lseek (fd, ehdr.e_phoff, SEEK_SET) != -1) |
| + sample_len = read (fd, phdr, |
| + nphdr * ehdr.e_phentsize); |
| + else |
| + sample_len = -1; |
| +#endif |
| + if (sample_len == nphdr * ehdr.e_phentsize) |
| + while (nphdr-- > 0) |
| + if (phdr[nphdr].p_type == PT_INTERP) |
| + { |
| + offset = phdr[nphdr].p_offset; |
| + break; |
| + } |
| + free (phdr); |
| + } |
| + } |
| + |
| + if (offset != -1) |
| + { |
| + size_t maxlen = 0; |
| + size_t actlen = 0; |
| + char *interp = NULL; |
| + |
| + do |
| + { |
| + if (actlen == maxlen) |
| + { |
| + char *newinterp = realloc (interp, maxlen += 200); |
| + if (newinterp == NULL) |
| + { |
| + actlen = 0; |
| + break; |
| + } |
| + interp = newinterp; |
| + |
| +#ifdef HAVE_PREAD |
| + actlen = pread (fd, interp, maxlen, offset); |
| +#else |
| + if (lseek (fd, offset, SEEK_SET) != -1) |
| + actlen = read (fd, interp, maxlen); |
| + else |
| + actlen = -1; |
| +#endif |
| + } |
| + } |
| + while (actlen > 0 && memchr (interp, '\0', actlen) == NULL); |
| + |
| + if (actlen > 0) |
| + { |
| + close (fd); |
| + errno = i; |
| + sys_error ("%s: %s: bad ELF interpreter", command, |
| + interp); |
| + free (interp); |
| + return (EX_NOEXEC); |
| + } |
| + |
| + free (interp); |
| + } |
| + } |
| +#endif |
| +#if defined (HAVE_HASH_BANG_EXEC) || defined (HAVE_ELF_H) |
| + close (fd); |
| +#endif |
| errno = i; |
| file_error (command); |
| } |
| -- |
| 2.9.3 |
| |