From: Kamil Dudka <kdudka@redhat.com>
To: zsh-workers@zsh.org
Subject: [PATCH 1/2] report bad ELF interpreter if it causes exec to fail
Date: Fri, 17 Apr 2015 15:25:54 +0200 [thread overview]
Message-ID: <1429277155-24607-1-git-send-email-kdudka@redhat.com> (raw)
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
next reply other threads:[~2015-04-17 13:26 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-04-17 13:25 Kamil Dudka [this message]
2015-04-17 13:25 ` [PATCH 2/2] clear the heredoc list in case par_event() fails Kamil Dudka
2015-04-17 19:17 ` Peter Stephenson
2015-04-20 8:48 ` Kamil Dudka
2018-11-29 16:24 ` Kamil Dudka
2018-11-29 17:34 ` Peter Stephenson
2018-11-29 18:39 ` Bart Schaefer
2018-11-30 9:55 ` Peter Stephenson
2018-11-30 12:53 ` Kamil Dudka
2015-04-17 13:49 ` [PATCH 1/2] report bad ELF interpreter if it causes exec to fail Daniel Shahaf
2015-04-17 14:32 ` Kamil Dudka
2015-04-17 15:21 ` Oliver Kiddle
2015-04-17 15:59 ` Kamil Dudka
2015-04-17 19:59 ` Oliver Kiddle
2015-04-17 15:41 ` Philippe Troin
2015-04-17 15:51 ` Bart Schaefer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1429277155-24607-1-git-send-email-kdudka@redhat.com \
--to=kdudka@redhat.com \
--cc=zsh-workers@zsh.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).