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