1 /* $OpenBSD: ksyms.c,v 1.1 2008/04/01 21:05:50 miod 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 #ifdef _NLIST_DO_ELF 27 #include <elf_abi.h> 28 #endif 29 30 #include "hangman.h" 31 32 int ksyms_aout_parse(); 33 int ksyms_elf_parse(); 34 35 void 36 kgetword() 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 = (double) random() / (RAND_MAX + 1.0) * (double)ksymsize; 46 if (lseek(ksyms, pos + ksymoffs, SEEK_SET) == -1) 47 continue; 48 buflen = read(ksyms, 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 >= ksymsize) 60 buflen = ksymsize - pos; 61 *(end = symbuf + buflen) = '\0'; 62 63 for (sym = symbuf; *sym != '\0'; sym++) ; 64 if (sym == end) 65 continue; 66 67 symlen = strlen(++sym); 68 if (symlen < MINLEN || symlen > MAXLEN) 69 continue; 70 71 break; 72 } 73 74 if (tries >= MAXBADWORDS) { 75 mvcur(0, COLS - 1, LINES -1, 0); 76 endwin(); 77 errx(1, "can't seem a suitable kernel symbol in %s", 78 Dict_name); 79 } 80 81 strlcpy(Word, sym, sizeof Word); 82 strlcpy(Known, sym, sizeof Known); 83 for (sym = Known; *sym != '\0'; sym++) { 84 if (*sym == '-') 85 *sym = '_'; /* try not to confuse player */ 86 if (isalpha(*sym)) 87 *sym = '-'; 88 } 89 } 90 91 int 92 ksetup() 93 { 94 if ((ksyms = open(Dict_name, O_RDONLY)) < 0) 95 return ksyms; 96 97 /* 98 * Relaxed header check - /dev/ksyms is either a native a.out 99 * binary or a native ELF binary. 100 */ 101 102 #ifdef _NLIST_DO_ELF 103 if (ksyms_elf_parse() == 0) 104 return 0; 105 #endif 106 107 #ifdef _NLIST_DO_AOUT 108 if (ksyms_aout_parse() == 0) 109 return 0; 110 #endif 111 112 close(ksyms); 113 errno = ENOEXEC; 114 return -1; 115 } 116 117 #ifdef _NLIST_DO_ELF 118 int 119 ksyms_elf_parse() 120 { 121 Elf_Ehdr eh; 122 Elf_Shdr sh; 123 uint s; 124 125 if (lseek(ksyms, 0, SEEK_SET) == -1) 126 return -1; 127 128 if (read(ksyms, &eh, sizeof eh) != sizeof eh) 129 return -1; 130 131 if (!IS_ELF(eh)) 132 return -1; 133 134 if (lseek(ksyms, eh.e_shoff, SEEK_SET) == -1) 135 return -1; 136 137 ksymoffs = 0; 138 ksymsize = 0; 139 140 for (s = 0; s < eh.e_shnum; s++) { 141 if (read(ksyms, &sh, sizeof sh) != sizeof sh) 142 return -1; 143 144 /* 145 * There should be two string table sections, one with the 146 * name of the sections themselves, and one with the symbol 147 * names. Just pick the largest one. 148 */ 149 if (sh.sh_type == SHT_STRTAB) { 150 if (ksymsize > (off_t)sh.sh_size) 151 continue; 152 153 ksymoffs = (off_t)sh.sh_offset; 154 ksymsize = (off_t)sh.sh_size; 155 } 156 } 157 158 if (ksymsize == 0) 159 return -1; 160 161 return 0; 162 } 163 #endif 164 165 #ifdef _NLIST_DO_AOUT 166 int 167 ksyms_aout_parse() 168 { 169 struct exec eh; 170 uint32_t size; 171 172 if (lseek(ksyms, 0, SEEK_SET) == -1) 173 return -1; 174 175 if (read(ksyms, &eh, sizeof eh) != sizeof eh) 176 return -1; 177 178 if (N_BADMAG(eh)) 179 return -1; 180 181 ksymoffs = (off_t)N_STROFF(eh); 182 if (lseek(ksyms, ksymoffs, SEEK_SET) == -1) 183 return -1; 184 185 if (read(ksyms, &size, sizeof size) != sizeof size) 186 return -1; 187 ksymoffs += sizeof size; 188 if (size <= sizeof size) 189 return -1; 190 ksymsize = (off_t)size - sizeof size; 191 192 return 0; 193 } 194 #endif 195