1 /* $OpenBSD: ksyms.c,v 1.4 2013/10/15 22:09:29 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 <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 int ksyms_elf_parse(); 31 32 void 33 kgetword() 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(ksymsize); 43 if (lseek(ksyms, pos + ksymoffs, SEEK_SET) == -1) 44 continue; 45 buflen = read(ksyms, 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 >= ksymsize) 57 buflen = ksymsize - pos; 58 *(end = symbuf + buflen) = '\0'; 59 60 for (sym = symbuf; *sym != '\0'; sym++) ; 61 if (sym == end) 62 continue; 63 64 symlen = strlen(++sym); 65 if (symlen < MINLEN || symlen > MAXLEN) 66 continue; 67 68 break; 69 } 70 71 if (tries >= MAXBADWORDS) { 72 mvcur(0, COLS - 1, LINES -1, 0); 73 endwin(); 74 errx(1, "can't seem a suitable kernel symbol in %s", 75 Dict_name); 76 } 77 78 strlcpy(Word, sym, sizeof Word); 79 strlcpy(Known, sym, sizeof Known); 80 for (sym = Known; *sym != '\0'; sym++) { 81 if (*sym == '-') 82 *sym = '_'; /* try not to confuse player */ 83 if (isalpha(*sym)) 84 *sym = '-'; 85 } 86 } 87 88 int 89 ksetup() 90 { 91 if ((ksyms = open(Dict_name, O_RDONLY)) < 0) 92 return ksyms; 93 94 if (ksyms_elf_parse() == 0) 95 return 0; 96 97 close(ksyms); 98 errno = ENOEXEC; 99 return -1; 100 } 101 102 int 103 ksyms_elf_parse() 104 { 105 Elf_Ehdr eh; 106 Elf_Shdr sh; 107 uint s; 108 109 if (lseek(ksyms, 0, SEEK_SET) == -1) 110 return -1; 111 112 if (read(ksyms, &eh, sizeof eh) != sizeof eh) 113 return -1; 114 115 if (!IS_ELF(eh)) 116 return -1; 117 118 if (lseek(ksyms, eh.e_shoff, SEEK_SET) == -1) 119 return -1; 120 121 ksymoffs = 0; 122 ksymsize = 0; 123 124 for (s = 0; s < eh.e_shnum; s++) { 125 if (read(ksyms, &sh, sizeof sh) != sizeof sh) 126 return -1; 127 128 /* 129 * There should be two string table sections, one with the 130 * name of the sections themselves, and one with the symbol 131 * names. Just pick the largest one. 132 */ 133 if (sh.sh_type == SHT_STRTAB) { 134 if (ksymsize > (off_t)sh.sh_size) 135 continue; 136 137 ksymoffs = (off_t)sh.sh_offset; 138 ksymsize = (off_t)sh.sh_size; 139 } 140 } 141 142 if (ksymsize == 0) 143 return -1; 144 145 return 0; 146 } 147