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 <elf_abi.h> 27 28 #include "hangman.h" 29 30 static int ksyms_elf_parse(void); 31 32 void 33 sym_getword() 34 { 35 uint tries; 36 off_t pos; 37 int buflen; 38 char symbuf[1 + BUFSIZ], *sym, *end; 39 size_t symlen; 40 41 for (tries = 0; tries < MAXBADWORDS; tries++) { 42 pos = arc4random_uniform(symsize); 43 if (lseek(symfd, pos + symoffs, SEEK_SET) == -1) 44 continue; 45 buflen = read(symfd, symbuf, BUFSIZ); 46 if (buflen < 0) 47 continue; 48 49 /* 50 * The buffer is hopefully large enough to hold at least 51 * a complete symbol, i.e. two occurences of NUL, or 52 * one occurence of NUL and the buffer containing the end 53 * of the string table. We make sure the buffer will be 54 * NUL terminated in all cases. 55 */ 56 if (buflen + pos >= symsize) 57 buflen = symsize - pos; 58 *(end = symbuf + buflen) = '\0'; 59 60 for (sym = symbuf; *sym != '\0'; sym++) 61 ; 62 if (sym == end) 63 continue; 64 65 symlen = strlen(++sym); 66 if (symlen < MINLEN || symlen > MAXLEN) 67 continue; 68 69 /* ignore symbols containing dots or dollar signs */ 70 if (strchr(sym, '.') != NULL || strchr(sym, '$') != NULL) 71 continue; 72 73 break; 74 } 75 76 if (tries >= MAXBADWORDS) { 77 mvcur(0, COLS - 1, LINES -1, 0); 78 endwin(); 79 errx(1, "can't seem a suitable symbol in %s", 80 Dict_name); 81 } 82 83 strlcpy(Word, sym, sizeof Word); 84 strlcpy(Known, sym, sizeof Known); 85 for (sym = Known; *sym != '\0'; sym++) { 86 if (*sym == '-') 87 *sym = '_'; /* try not to confuse player */ 88 if (isalnum((unsigned char)*sym)) 89 *sym = '-'; 90 } 91 } 92 93 int 94 sym_setup() 95 { 96 if ((symfd = open(Dict_name, O_RDONLY)) < 0) 97 return -1; 98 99 if (ksyms_elf_parse() == 0) 100 return 0; 101 102 close(symfd); 103 errno = ENOEXEC; 104 return -1; 105 } 106 107 int 108 ksyms_elf_parse() 109 { 110 Elf_Ehdr eh; 111 Elf_Shdr sh; 112 uint s; 113 114 if (lseek(symfd, 0, SEEK_SET) == -1) 115 return -1; 116 117 if (read(symfd, &eh, sizeof eh) != sizeof eh) 118 return -1; 119 120 if (!IS_ELF(eh)) 121 return -1; 122 123 if (lseek(symfd, eh.e_shoff, SEEK_SET) == -1) 124 return -1; 125 126 symoffs = 0; 127 symsize = 0; 128 129 for (s = 0; s < eh.e_shnum; s++) { 130 if (read(symfd, &sh, sizeof sh) != sizeof sh) 131 return -1; 132 133 /* 134 * There should be two string table sections, one with the 135 * name of the sections themselves, and one with the symbol 136 * names. Just pick the largest one. 137 */ 138 if (sh.sh_type == SHT_STRTAB) { 139 if (symsize > (off_t)sh.sh_size) 140 continue; 141 142 symoffs = (off_t)sh.sh_offset; 143 symsize = (off_t)sh.sh_size; 144 } 145 } 146 147 if (symsize == 0) 148 return -1; 149 150 return 0; 151 } 152