about summary refs log tree commit diff
path: root/sysdeps/powerpc/powerpc64/check-execstack.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/powerpc/powerpc64/check-execstack.c')
-rw-r--r--sysdeps/powerpc/powerpc64/check-execstack.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/sysdeps/powerpc/powerpc64/check-execstack.c b/sysdeps/powerpc/powerpc64/check-execstack.c
new file mode 100644
index 0000000000..81947894cc
--- /dev/null
+++ b/sysdeps/powerpc/powerpc64/check-execstack.c
@@ -0,0 +1,195 @@
+/* Verify nonexecutable stack in test app when linked against GLIBC.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contribute by Ryan S. Arnold <rsa@us.ibm.com>. 2010.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#if defined HAVE_PPC64_PT_GNU_STACK
+
+/* If the compiler defaults to emitting PT_GNU_STACK for PPC64 then we should
+ * use the standard check-execstack.c test case which checks the shared objects
+ * generated by GLIBC for the GNU_STACK header.  */
+#include "../../../elf/check-execstack.c"
+
+#else
+
+/* The original test in elf/check-execstack.c supposedly checks for no-exec
+ * stack but what it really does is check if the compiler used to to build GLIBC
+ * creates a PT_GNU_STACK header in the elf info for each shared object.  The
+ * only way to check whether the stack is executable is to build and link an app
+ * with the recently built GLIBC and check the exec bits.  */
+
+#include <stdio.h>
+#include <byteswap.h>
+#include <elf.h>
+#include <endian.h>
+#include <linux/limits.h> /* Pick up PATH_MAX.  */
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <alloca.h>
+
+/* Macros taken from elf/check-execstack.c because it works.  */
+# define BITS 64
+# define E(name) _E (name, BITS)
+# define _E(name, bits) __E (name, bits)
+# define __E(name, bits) Elf##bits##_##name
+# define SWAP(val) \
+  ({ __typeof (val) __res;						      \
+     if (((ehdr.e_ident[EI_DATA] == ELFDATA2MSB				      \
+	   && BYTE_ORDER == LITTLE_ENDIAN)				      \
+	  || (ehdr.e_ident[EI_DATA] == ELFDATA2LSB			      \
+	      && BYTE_ORDER == BIG_ENDIAN))				      \
+	 && sizeof (val) != 1)						      \
+       {								      \
+	 if (sizeof (val) == 2)						      \
+	   __res = bswap_16 (val);					      \
+	 else if (sizeof (val) == 4)					      \
+	   __res = bswap_32 (val);					      \
+	 else								      \
+	   __res = bswap_64 (val);					      \
+       }								      \
+     else								      \
+       __res = (val);							      \
+     __res; })
+
+/* Make sure this binary doesn't have PT_GNU_STACK set (which it shouldn't if
+ * the configure test which left HAVE_PPC64_PT_GNU_STACK unset was correct) and
+ * make sure that this test case didn't inherit PT_GNU_STACK, and that the stack
+ * defaults to non-executable anyway.  */
+
+int
+main (int argc, char *argv[])
+{
+
+  char *argv0 = argv[0]; /* testcase binary.  */
+  int fd = open (argv0, O_RDONLY);
+
+  if (fd == -1)
+    {
+      printf("Cannot open file image %s for reading.\n", argv0);
+    }
+
+  /* Read whats is supposed to be the ELF header.  Read the initial
+     bytes to determine whether this is a 32 or 64 bit file.  */
+  char ident[EI_NIDENT];
+  if (read (fd, ident, EI_NIDENT) != EI_NIDENT)
+    {
+    read_error:
+      printf("%s: read error\n", argv0);
+      close (fd);
+      return 1;
+    }
+
+  if (memcmp (&ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
+    {
+      printf("%s: not an ELF file\n", argv0);
+      close (fd);
+      return 1;
+    }
+
+  /* Only operate on a 64-bit file.  */
+  if (ident[EI_CLASS] == ELFCLASS32)
+    {
+      printf("%s is not a 64-bit binary.\n",argv0);
+      close (fd);
+      return 1;
+  }
+
+  /* Now verify that this binary doesn't have a PT_GNU_STACK header.  */
+  E(Ehdr) ehdr;
+
+  if (pread (fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
+    goto read_error;
+
+  const size_t phnum = SWAP (ehdr.e_phnum);
+  const size_t phentsize = SWAP (ehdr.e_phentsize);
+
+  /* Read the program header.  */
+  E(Phdr) *phdr = alloca (phentsize * phnum);
+  if (pread (fd, phdr, phentsize * phnum, SWAP (ehdr.e_phoff))
+      != phentsize * phnum)
+    goto read_error;
+
+  /* Search for an unwanted PT_GNU_STACK entry.  */
+  for (size_t cnt = 0; cnt < phnum; ++cnt)
+    if (SWAP (phdr[cnt].p_type) == PT_GNU_STACK)
+      {
+	printf("%s: Found unwanted PT_GNU_STACK header.\n", argv0);
+	close (fd);
+	return 1;
+      }
+
+  close(fd);
+
+  /* Now make sure the stack is marked non-executable by reading
+   * /proc/self/maps and looking for the memory permissions on the [stack]
+   * region.  */
+
+  FILE *mapfd = fopen ("/proc/self/maps", "r");
+  if (mapfd == NULL)
+    {
+      /* We don't have a solution for older systems that don't support
+       * /proc/self/maps.  Just return a false success since the situation is
+       * kind of ridiculous (really old kernel + glibc 2.13+).  */
+      printf("fopen of /proc/self/maps failed.\n");
+      return 0;
+    }
+
+  char line[PATH_MAX + 128];
+  const char delimiters[] = " ";
+  char *token;
+  const char stack[] = "[stack]";
+  while ((fgets(line, PATH_MAX + 128, mapfd)) != NULL)
+    {
+      char *perms = NULL;
+      int field = 0;
+      token = strtok(line,delimiters);
+      while(token != NULL) {
+	if (field == 1) /* The second field is the perms field.  */
+	  perms = token; /* Save this until we find [stack].  */
+	if (field == 5) /* The sixth field is the pathname field.  */
+	  {
+	    /* If we find "[stack]" as the pathname check the permissions.  */
+	    if (!strncmp(stack,token,strlen(stack)))
+	      {
+		if (perms[2] == 'x')
+		  {
+		    printf("found executable stack for %s.\n", argv0);
+		    printf("%s %s %s\n",line,perms,token);
+		    fclose(mapfd);
+		    return 1;
+		  }
+		else
+		  {
+		    printf("found noexec stack in:\n");
+		    printf("%s %s %s\n",line,perms,token);
+		    fclose(mapfd);
+		    return 0;
+		  }
+	      }
+	    break;
+	  }
+	token = strtok(NULL,delimiters);
+	field++;
+      }
+    }
+  printf("didn't find [stack] pathname for %s in /proc/self/maps.\n", argv0);
+  fclose(mapfd);
+  return 1;
+}
+#endif