Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH 1/2] report bad ELF interpreter if it causes exec to fail
- X-seq: zsh-workers 34909
- From: Kamil Dudka <kdudka@xxxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: [PATCH 1/2] report bad ELF interpreter if it causes exec to fail
- Date: Fri, 17 Apr 2015 15:25:54 +0200
- List-help: <mailto:zsh-workers-help@zsh.org>
- List-id: Zsh Workers List <zsh-workers.zsh.org>
- List-post: <mailto:zsh-workers@zsh.org>
- Mailing-list: contact zsh-workers-help@xxxxxxx; run by ezmlm
This is already implemented <https://bugzilla.redhat.com/60870> in some
distributions of bash and tcsh <https://bugzilla.redhat.com/711066>.
Steps to reproduce:
echo 'int main () { return 0; }' > u.c
gcc -o u u.c -Wl,-dynamic-linker,/foo/bar/baz
zsh -c ./u
Bug: https://bugzilla.redhat.com/711067
---
Src/exec.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
configure.ac | 2 +-
2 files changed, 131 insertions(+), 4 deletions(-)
diff --git a/Src/exec.c b/Src/exec.c
index 2a8185c..18408d7 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -30,6 +30,10 @@
#include "zsh.mdh"
#include "exec.pro"
+#ifdef HAVE_ELF_H
+# include <elf.h>
+#endif
+
/* Flags for last argument of addvars */
enum {
@@ -427,6 +431,112 @@ execcursh(Estate state, int do_exec)
return lastval;
}
+/* The following code is taken from <https://bugzilla.redhat.com/60870>. */
+#ifdef HAVE_ELF_H
+static int
+checkelfinterp(const char *pth, int fd, const char *sample, int sample_len)
+{
+ off_t offset = -1;
+ int eno = ENOENT;
+
+ /* Read the offset of the interpreter string. */
+ if (sample[EI_CLASS] == ELFCLASS32 && sample_len >= sizeof(Elf32_Ehdr)) {
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr *phdr;
+ Elf32_Half 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 *) zalloc((size_t)nphdr * (size_t)ehdr.e_phentsize);
+ if (phdr != NULL) {
+ if (lseek(fd, ehdr.e_phoff, SEEK_SET) != -1)
+ sample_len = read(fd, phdr, nphdr * ehdr.e_phentsize);
+ else
+ sample_len = -1;
+
+ 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;
+ Elf32_Half 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 *) zalloc((size_t)nphdr * (size_t)ehdr.e_phentsize);
+ if (phdr != NULL) {
+ if (lseek(fd, ehdr.e_phoff, SEEK_SET) != -1)
+ sample_len = read(fd, phdr,
+ nphdr * ehdr.e_phentsize);
+ else
+ sample_len = -1;
+
+ 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) {
+ ssize_t maxlen = 0;
+ ssize_t actlen = 0;
+ ssize_t nread = 0;
+ off_t pos = 0;
+ char *interp = NULL;
+
+ for (;;) {
+ if (actlen >= maxlen) {
+ char *newinterp = zrealloc(interp, maxlen += 200);
+ if (newinterp == NULL)
+ /* out of memroy */
+ break;
+ interp = newinterp;
+ }
+
+ if (lseek(fd, offset + pos, SEEK_SET) == -1)
+ break;
+
+ if ((nread = read(fd, interp + pos, maxlen - pos)) == -1)
+ break;
+
+ if (memchr(interp + pos, '\0', nread) != NULL) {
+ zerr("%s: %s: bad ELF interpreter", pth, interp);
+ eno = ENOEXEC;
+ break;
+ }
+
+ actlen += nread;
+ pos += nread;
+ }
+
+ free(interp);
+ }
+
+ return eno;
+}
+#endif
+
/* execve after handling $_ and #! */
#define POUNDBANGLIMIT 64
@@ -468,12 +578,20 @@ zexecve(char *pth, char **argv, char **newenvp)
int fd, ct, t0;
if ((fd = open(pth, O_RDONLY|O_NOCTTY)) >= 0) {
+ size_t hdrsize = POUNDBANGLIMIT;
+#ifdef HAVE_ELF_H
+ /* Inspect 32 and 64 ELF */
+ if (sizeof(Elf64_Ehdr) > hdrsize)
+ hdrsize = sizeof(Elf64_Ehdr);
+ if (sizeof(Elf32_Ehdr) > hdrsize)
+ hdrsize = sizeof(Elf32_Ehdr);
+#endif
argv0 = *argv;
*argv = pth;
- ct = read(fd, execvebuf, POUNDBANGLIMIT);
- close(fd);
+ ct = read(fd, execvebuf, hdrsize);
if (ct > 0) {
if (execvebuf[0] == '#') {
+ close(fd);
if (execvebuf[1] == '!') {
for (t0 = 0; t0 != ct; t0++)
if (execvebuf[t0] == '\n')
@@ -513,6 +631,7 @@ zexecve(char *pth, char **argv, char **newenvp)
execve("/bin/sh", argv - 1, newenvp);
}
} else if (eno == ENOEXEC) {
+ close(fd);
for (t0 = 0; t0 != ct; t0++)
if (!execvebuf[t0])
break;
@@ -521,7 +640,15 @@ zexecve(char *pth, char **argv, char **newenvp)
winch_unblock();
execve("/bin/sh", argv - 1, newenvp);
}
- }
+#ifdef HAVE_ELF_H
+ } else if (eno == ENOENT
+ && ct > EI_NIDENT
+ && memcmp(execvebuf, ELFMAG, SELFMAG) == 0) {
+ eno = checkelfinterp(pth, fd, execvebuf, ct);
+ close(fd);
+#endif
+ } else
+ close(fd);
} else
eno = errno;
*argv = argv0;
diff --git a/configure.ac b/configure.ac
index e4de193..645385d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -676,7 +676,7 @@ AC_CHECK_HEADERS(sys/time.h sys/times.h sys/select.h termcap.h termio.h \
utmp.h utmpx.h sys/types.h pwd.h grp.h poll.h sys/mman.h \
netinet/in_systm.h pcre.h langinfo.h wchar.h stddef.h \
sys/stropts.h iconv.h ncurses.h ncursesw/ncurses.h \
- ncurses/ncurses.h)
+ ncurses/ncurses.h elf.h)
if test x$dynamic = xyes; then
AC_CHECK_HEADERS(dlfcn.h)
AC_CHECK_HEADERS(dl.h)
--
2.1.0
Messages sorted by:
Reverse Date,
Date,
Thread,
Author