Blob Blame History Raw
From b913dff5f7c123691b9aea3cee4bf270bc56659b Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Wed, 27 Aug 2014 13:55:10 +0200
Subject: [PATCH 12/14] report missing ELF interpreter

Resolves: #711066

Adjusted for tcsh-6.19.00 by Fridolin Pokorny <fpokorny@redhat.com>

---
 configure.in |   5 ++-
 sh.err.c     |   4 +-
 sh.exec.c    | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 152 insertions(+), 3 deletions(-)

diff --git a/sh.err.c b/sh.err.c
index 29d41c3..262f9bf 100644
--- a/sh.err.c
+++ b/sh.err.c
@@ -189,7 +189,8 @@ char   *seterr = NULL;	/* Holds last error if there was one */
 #define ERR_INVALID	133
 #define ERR_BADCOLORVAR	134
 #define ERR_EOF		135
-#define NO_ERRORS	136
+#define ERR_ELFINTERP	136
+#define NO_ERRORS	137
 
 static const char *elst[NO_ERRORS] INIT_ZERO_STRUCT;
 
@@ -367,6 +368,7 @@ errinit(void)
     elst[ERR_BADJOB] = CSAVS(1, 136, "No such job (badjob)");
     elst[ERR_BADCOLORVAR] = CSAVS(1, 137, "Unknown colorls variable `%c%c'");
     elst[ERR_EOF] = CSAVS(1, 138, "Unexpected end of file");
+    elst[ERR_ELFINTERP] = CSAVS(1, 139, "No such ELF interpreter");
 }
 
 /* Cleanup data. */
diff --git a/sh.exec.c b/sh.exec.c
index 2b41a53..c1f4b7e 100644
--- a/sh.exec.c
+++ b/sh.exec.c
@@ -40,6 +40,10 @@ RCSID("$tcsh: sh.exec.c,v 3.79 2011/02/25 23:58:34 christos Exp $")
 #include <nt.const.h>
 #endif /*WINNT_NATIVE*/
 
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif /*HAVE_ELF_H*/
+
 /*
  * C shell
  */
@@ -509,6 +513,142 @@ texec(Char *sf, Char **st)
     case 0:			/* execv fails and returns 0! */
 #endif /* _IBMR2 */
     case ENOENT:
+#ifdef HAVE_ELF_H
+	/*
+	 * If dynamically linked ELF binary is not executed and exists,
+	 * the real reason ENOENT is that ELF interpreter is missing.
+	 *
+	 * Written by Ulrich Drepper for bash
+	 * adopted by Fridolin Pokorny <fpokorny@redhat.com>
+	 */
+	if ((fd = xopen(f, O_RDONLY|O_LARGEFILE)) != -1) {
+	    int nread;
+	    char *sample;
+	    int offset = -1;
+	    int sample_size;
+
+	    /* Inspect 32 and 64 ELF */
+	    if (sizeof(Elf64_Ehdr) > sizeof(Elf32_Ehdr))
+		sample_size = sizeof(Elf64_Ehdr);
+	    else
+		sample_size = sizeof(Elf32_Ehdr);
+
+	    sample = xmalloc(sample_size);
+
+	    if (sample != 0 &&
+		    (nread = xread(fd, sample, sample_size)) == sample_size) {
+		if (memcmp(sample, ELFMAG, SELFMAG) == 0) {
+		    if (sample[EI_CLASS] == ELFCLASS32 &&
+			    sample_size >= 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 = xmalloc(nphdr * ehdr.e_phentsize);
+			if(phdr != NULL) {
+#ifdef HAVE_PREAD
+			    nread = pread(fd, phdr, nphdr * ehdr.e_phentsize,
+					  ehdr.e_phoff);
+#else /* !HAVE_PREAD */
+			    if (lseek(fd, ehdr.e_phoff, SEEK_SET) != -1)
+				nread = read(fd, phdr,
+					   nphdr * ehdr.e_phentsize);
+			    else
+				nread = -1;
+#endif /* HAVE_PREAD */
+			    if (nread == nphdr * ehdr.e_phentsize) {
+				while (nphdr-- > 0) {
+				    if (phdr[nphdr].p_type == PT_INTERP) {
+					offset = phdr[nphdr].p_offset;
+					break;
+				    }
+				}
+			    }
+			    xfree(phdr);
+			}
+		    } else if (sample[EI_CLASS] == ELFCLASS64 &&
+			    sample_size >= 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 = xmalloc(nphdr * ehdr.e_phentsize);
+			if (phdr != NULL) {
+#ifdef HAVE_PREAD
+			    nread = pread (fd, phdr, nphdr * ehdr.e_phentsize,
+					  ehdr.e_phoff);
+#else /* !HAVE_PREAD */
+			    if (lseek(fd, ehdr.e_phoff, SEEK_SET) != -1)
+				nread = read (fd, phdr,
+					   nphdr * ehdr.e_phentsize);
+			    else
+				nread = -1;
+#endif /* HAVE_PREAD */
+			    if (nread == nphdr * ehdr.e_phentsize) {
+				while (nphdr-- > 0) {
+				  if (phdr[nphdr].p_type == PT_INTERP) {
+				      offset = phdr[nphdr].p_offset;
+				      break;
+				    }
+				}
+			    }
+			    xfree (phdr);
+			}
+		    }
+
+		    if (offset != -1) {
+			size_t maxlen = 0;
+			size_t actlen = 0;
+			char *interp = NULL;
+
+			do {
+			    if (actlen == maxlen) {
+				char *newinterp = xrealloc(interp, maxlen += 200);
+				if (newinterp == NULL) {
+				    actlen = 0;
+				    break;
+				}
+				interp = newinterp;
+#ifdef HAVE_PREAD
+				actlen = pread (fd, interp, maxlen, offset);
+#else /* !HAVE_PREAD */
+				if (lseek (fd, offset, SEEK_SET) != -1)
+				    actlen = read (fd, interp, maxlen);
+				else
+				    actlen = -1;
+#endif /* HAVE_PREAD */
+			    }
+			} while (actlen > 0 &&
+				memchr (interp, '\0', actlen) == NULL);
+
+			if (actlen > 0) {
+			    xclose (fd);
+			    xfree (interp);
+			    setname(f);
+			    stderror(ERR_NAME | ERR_ELFINTERP);
+			}
+		    }
+		}
+	    }
+	    xfree(sample);
+	}
+#endif /* HAVE_ELF_H */
 	break;
 
     default:
-- 
1.9.3