1 /* $OpenBSD: kvm_mkdb.c,v 1.33 2021/10/24 21:24:18 deraadt Exp $ */
2
3 /*-
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36
37 #include <db.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <libgen.h>
42 #include <paths.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <grp.h>
48
49 #include "extern.h"
50
51 __dead void usage(void);
52 int kvm_mkdb(int, const char *, char *, char *, gid_t, int);
53
54 HASHINFO openinfo = {
55 4096, /* bsize */
56 128, /* ffactor */
57 1024, /* nelem */
58 2048 * 1024, /* cachesize */
59 NULL, /* hash() */
60 0 /* lorder */
61 };
62
63 int
main(int argc,char * argv[])64 main(int argc, char *argv[])
65 {
66 struct rlimit rl;
67 struct group *gr;
68 gid_t kvm_gid = -1;
69 int fd, rval, ch, verbose = 0;
70 char *nlistpath, *nlistname;
71 char dbdir[PATH_MAX];
72
73 if (pledge("stdio rpath wpath cpath fattr getpw flock id unveil", NULL) == -1)
74 err(1, "pledge");
75
76 /* Try to use the kmem group to be able to fchown() in kvm_mkdb(). */
77 if ((gr = getgrnam("kmem")) == NULL) {
78 warn("can't find kmem group");
79 } else {
80 kvm_gid = gr->gr_gid;
81 if (setresgid(kvm_gid, kvm_gid, kvm_gid) == -1)
82 err(1, "setresgid");
83 }
84
85 /* Increase our data size to the max if we can. */
86 if (getrlimit(RLIMIT_DATA, &rl) == 0) {
87 rl.rlim_cur = rl.rlim_max;
88 if (setrlimit(RLIMIT_DATA, &rl) == -1)
89 warn("can't set rlimit data size");
90 }
91
92 if (pledge("stdio rpath wpath cpath fattr flock unveil", NULL) == -1)
93 err(1, "pledge");
94
95 strlcpy(dbdir, _PATH_VARDB, sizeof(dbdir));
96 while ((ch = getopt(argc, argv, "vo:")) != -1)
97 switch (ch) {
98 case 'v':
99 verbose = 1;
100 break;
101 case 'o':
102 rval = strlcpy(dbdir, optarg, sizeof(dbdir));
103 if (rval == 0 || rval + 1 >= sizeof(dbdir))
104 errx(1, "Invalid directory");
105 /* Make sure there is a '/' at the end of the path */
106 if (dbdir[strlen(dbdir) - 1] != '/')
107 strlcat(dbdir, "/", sizeof(dbdir));
108 break;
109 default:
110 usage();
111 }
112 argc -= optind;
113 argv += optind;
114
115 if (argc > 1)
116 usage();
117
118 if (argc > 0) {
119 if (unveil(argv[0], "r") == -1)
120 err(1, "unveil %s", argv[0]);
121 } else {
122 if (unveil(_PATH_UNIX, "r") == -1)
123 err(1, "unveil %s", _PATH_UNIX);
124 if (unveil(_PATH_KSYMS, "r") == -1)
125 err(1, "unveil %s", _PATH_KSYMS);
126 }
127 if (unveil(dbdir, "rwc") == -1)
128 err(1, "unveil %s", dbdir);
129 if (pledge("stdio rpath wpath cpath fattr flock", NULL) == -1)
130 err(1, "pledge");
131
132 /* If no kernel specified use _PATH_KSYMS and fall back to _PATH_UNIX */
133 if (argc > 0) {
134 nlistpath = argv[0];
135 nlistname = basename(nlistpath);
136 if ((fd = open(nlistpath, O_RDONLY)) == -1)
137 err(1, "can't open %s", nlistpath);
138 rval = kvm_mkdb(fd, dbdir, nlistpath, nlistname, kvm_gid,
139 verbose);
140 } else {
141 nlistname = basename(_PATH_UNIX);
142 if ((fd = open((nlistpath = _PATH_KSYMS), O_RDONLY)) == -1 ||
143 (rval = kvm_mkdb(fd, dbdir, nlistpath, nlistname, kvm_gid,
144 verbose)) != 0) {
145 if (fd == -1)
146 warnx("can't open %s", _PATH_KSYMS);
147 else
148 warnx("will try again using %s instead", _PATH_UNIX);
149 if ((fd = open((nlistpath = _PATH_UNIX), O_RDONLY)) == -1)
150 err(1, "can't open %s", nlistpath);
151 rval = kvm_mkdb(fd, dbdir, nlistpath, nlistname,
152 kvm_gid, verbose);
153 }
154 }
155 exit(rval);
156 }
157
158 int
kvm_mkdb(int fd,const char * dbdir,char * nlistpath,char * nlistname,gid_t gid,int verbose)159 kvm_mkdb(int fd, const char *dbdir, char *nlistpath, char *nlistname, gid_t gid,
160 int verbose)
161 {
162 DB *db;
163 char dbtemp[PATH_MAX], dbname[PATH_MAX];
164 int r;
165
166 r = snprintf(dbtemp, sizeof(dbtemp), "%skvm_%s.tmp",
167 dbdir, nlistname);
168 if (r < 0 || r >= sizeof(dbtemp)) {
169 warnx("Directory name too long");
170 return (1);
171 }
172 r = snprintf(dbname, sizeof(dbname), "%skvm_%s.db",
173 dbdir, nlistname);
174 if (r < 0 || r >= sizeof(dbtemp)) {
175 warnx("Directory name too long");
176 return (1);
177 }
178
179 /* If the existing db file matches the currently running kernel, exit */
180 if (testdb(dbname)) {
181 if (verbose)
182 warnx("%s already up to date", dbname);
183 return(0);
184 } else if (verbose)
185 warnx("rebuilding %s", dbname);
186
187 (void)umask(0);
188 db = dbopen(dbtemp, O_CREAT | O_EXLOCK | O_TRUNC | O_RDWR,
189 S_IRUSR | S_IWUSR | S_IRGRP, DB_HASH, &openinfo);
190 if (db == NULL) {
191 warn("can't dbopen %s", dbtemp);
192 return(1);
193 }
194
195 if (gid != -1 && fchown(db->fd(db), -1, gid) == -1) {
196 warn("can't chown %s", dbtemp);
197 (void)unlink(dbtemp);
198 return(1);
199 }
200
201 if (create_knlist(nlistpath, fd, db) != 0) {
202 warn("cannot determine executable type of %s", nlistpath);
203 (void)unlink(dbtemp);
204 return(1);
205 }
206 if (db->close(db)) {
207 warn("can't dbclose %s", dbtemp);
208 (void)unlink(dbtemp);
209 return(1);
210 }
211
212 if (rename(dbtemp, dbname)) {
213 warn("rename %s to %s", dbtemp, dbname);
214 (void)unlink(dbtemp);
215 return(1);
216 }
217
218 return(0);
219 }
220
221 __dead void
usage(void)222 usage(void)
223 {
224 (void)fprintf(stderr, "usage: kvm_mkdb [-v] [-o directory] [file]\n");
225 exit(1);
226 }
227