1 /* $OpenBSD: ksyms.c,v 1.13 2021/12/24 23:01:56 tb 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
sym_getword(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 /* ignore all double unberbar symbols */
74 if (strncmp(sym, "__", 2) == 0)
75 continue;
76
77 break;
78 }
79
80 if (tries >= MAXBADWORDS) {
81 mvcur(0, COLS - 1, LINES -1, 0);
82 endwin();
83 errx(1, "can't seem a suitable symbol in %s",
84 Dict_name);
85 }
86
87 strlcpy(Word, sym, sizeof Word);
88 strlcpy(Known, sym, sizeof Known);
89 for (sym = Known; *sym != '\0'; sym++) {
90 if (*sym == '-')
91 *sym = '_'; /* try not to confuse player */
92 if (isalnum((unsigned char)*sym))
93 *sym = '-';
94 }
95 }
96
97 int
sym_setup(void)98 sym_setup(void)
99 {
100 if ((symfd = open(Dict_name, O_RDONLY)) == -1)
101 return -1;
102
103 if (ksyms_elf_parse() == 0)
104 return 0;
105
106 close(symfd);
107 errno = ENOEXEC;
108 return -1;
109 }
110
111 int
ksyms_elf_parse(void)112 ksyms_elf_parse(void)
113 {
114 Elf_Ehdr eh;
115 Elf_Shdr sh;
116 uint s;
117
118 if (lseek(symfd, 0, SEEK_SET) == -1)
119 return -1;
120
121 if (read(symfd, &eh, sizeof eh) != sizeof eh)
122 return -1;
123
124 if (!IS_ELF(eh))
125 return -1;
126
127 if (lseek(symfd, eh.e_shoff, SEEK_SET) == -1)
128 return -1;
129
130 symoffs = 0;
131 symsize = 0;
132
133 for (s = 0; s < eh.e_shnum; s++) {
134 if (read(symfd, &sh, sizeof sh) != sizeof sh)
135 return -1;
136
137 /*
138 * There should be two string table sections, one with the
139 * name of the sections themselves, and one with the symbol
140 * names. Just pick the largest one.
141 */
142 if (sh.sh_type == SHT_STRTAB) {
143 if (symsize > (off_t)sh.sh_size)
144 continue;
145
146 symoffs = (off_t)sh.sh_offset;
147 symsize = (off_t)sh.sh_size;
148 }
149 }
150
151 if (symsize == 0)
152 return -1;
153
154 return 0;
155 }
156