diff options
Diffstat (limited to 'sysdeps/powerpc/powerpc64/check-execstack.c')
-rw-r--r-- | sysdeps/powerpc/powerpc64/check-execstack.c | 195 |
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 |