1 /* $OpenBSD: ksyms.c,v 1.8 2015/02/07 03:26:20 tedu Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Miodrag Vallat. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <unistd.h> 20 #include <ctype.h> 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <string.h> 24 25 #include <sys/exec.h> 26 #include <sys/elf64.h> 27 28 #include "hangman.h" 29 30 typedef Elf64_Ehdr Elf_Ehdr; 31 typedef Elf64_Shdr Elf_Shdr; 32 33 static int ksyms_elf_parse(void); 34 35 void 36 sym_getword(void) 37 { 38 uint tries; 39 off_t pos; 40 int buflen; 41 char symbuf[1 + BUFSIZ], *sym, *end; 42 size_t symlen; 43 44 for (tries = 0; tries < MAXBADWORDS; tries++) { 45 pos = arc4random_uniform(symsize); 46 if (lseek(symfd, pos + symoffs, SEEK_SET) == -1) 47 continue; 48 buflen = read(symfd, symbuf, BUFSIZ); 49 if (buflen < 0) 50 continue; 51 52 /* 53 * The buffer is hopefully large enough to hold at least 54 * a complete symbol, i.e. two occurences of NUL, or 55 * one occurence of NUL and the buffer containing the end 56 * of the string table. We make sure the buffer will be 57 * NUL terminated in all cases. 58 */ 59 if (buflen + pos >= symsize) 60 buflen = symsize - pos; 61 *(end = symbuf + buflen) = '\0'; 62 63 for (sym = symbuf; *sym != '\0'; sym++) 64 ; 65 if (sym == end) 66 continue; 67 68 symlen = strlen(++sym); 69 if (symlen < MINLEN || symlen > MAXLEN) 70 continue; 71 72 /* ignore symbols containing dots or dollar signs */ 73 if (strchr(sym, '.') != NULL || strchr(sym, '$') != NULL) 74 continue; 75 76 break; 77 } 78 79 if (tries >= MAXBADWORDS) { 80 mvcur(0, COLS - 1, LINES -1, 0); 81 endwin(); 82 errx(1, "can't seem a suitable symbol in %s", 83 Dict_name); 84 } 85 86 strlcpy(Word, sym, sizeof(Word)); 87 strlcpy(Known, sym, sizeof(Known)); 88 for (sym = Known; *sym != '\0'; sym++) { 89 if (*sym == '-') 90 *sym = '_'; /* try not to confuse player */ 91 if (isalnum((unsigned char)*sym)) 92 *sym = '-'; 93 } 94 } 95 96 int 97 sym_setup(void) 98 { 99 if ((symfd = open(Dict_name, O_RDONLY)) < 0) 100 return -1; 101 102 if (ksyms_elf_parse() == 0) 103 return 0; 104 105 close(symfd); 106 errno = ENOEXEC; 107 return -1; 108 } 109 110 int 111 ksyms_elf_parse(void) 112 { 113 Elf_Ehdr eh; 114 Elf_Shdr sh; 115 uint s; 116 117 if (lseek(symfd, 0, SEEK_SET) == -1) 118 return -1; 119 120 if (read(symfd, &eh, sizeof(eh)) != sizeof(eh)) 121 return -1; 122 123 if (!IS_ELF(eh)) 124 return -1; 125 126 if (lseek(symfd, eh.e_shoff, SEEK_SET) == -1) 127 return -1; 128 129 symoffs = 0; 130 symsize = 0; 131 132 for (s = 0; s < eh.e_shnum; s++) { 133 if (read(symfd, &sh, sizeof(sh)) != sizeof(sh)) 134 return -1; 135 136 /* 137 * There should be two string table sections, one with the 138 * name of the sections themselves, and one with the symbol 139 * names. Just pick the largest one. 140 */ 141 if (sh.sh_type == SHT_STRTAB) { 142 if (symsize > (off_t)sh.sh_size) 143 continue; 144 145 symoffs = (off_t)sh.sh_offset; 146 symsize = (off_t)sh.sh_size; 147 } 148 } 149 150 if (symsize == 0) 151 return -1; 152 153 return 0; 154 } 155