xref: /freebsd/sys/kern/kern_linker.c (revision ce834215a70ff69e7e222827437116eee2f9ac6f)
1 /*-
2  * Copyright (c) 1997 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	$Id$
27  */
28 
29 #include <sys/param.h>
30 #include <sys/kernel.h>
31 #include <sys/systm.h>
32 #include <sys/sysctl.h>
33 #include <sys/queue.h>
34 #include <sys/libkern.h>
35 #include <sys/malloc.h>
36 #include <sys/sysproto.h>
37 #include <sys/sysent.h>
38 #include <sys/proc.h>
39 #include <sys/lock.h>
40 #include <machine/cpu.h>
41 #include <sys/module.h>
42 #include <sys/linker.h>
43 
44 static struct lock lock;	/* lock for the file list */
45 static linker_class_list_t classes;
46 static linker_file_list_t files;
47 static int next_file_id = 1;
48 
49 static void
50 linker_init(void* arg)
51 {
52     lockinit(&lock, PVM, "klink", 0, 0);
53     TAILQ_INIT(&classes);
54     TAILQ_INIT(&files);
55 }
56 
57 SYSINIT(linker, SI_SUB_KMEM, SI_ORDER_SECOND, linker_init, 0);
58 
59 int
60 linker_add_class(const char* desc, void* priv,
61 		 struct linker_class_ops* ops)
62 {
63     linker_class_t lc;
64 
65     lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT);
66     if (!lc)
67 	return ENOMEM;
68 
69     lc->desc = desc;
70     lc->priv = priv;
71     lc->ops = ops;
72     TAILQ_INSERT_HEAD(&classes, lc, link);
73 
74     return 0;
75 }
76 
77 static void
78 linker_file_sysinit(linker_file_t lf)
79 {
80     struct linker_set* sysinits;
81     struct sysinit** sipp;
82     struct sysinit** xipp;
83     struct sysinit* save;
84     int rval[2];		/* SI_TYPE_KTHREAD support*/
85 
86     linker_current_file = lf;
87 
88     KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
89 		   lf->filename));
90 
91     sysinits = (struct linker_set*)
92 	linker_file_lookup_symbol(lf, "sysinit_set", 0);
93     if (!sysinits)
94 	return;
95 
96     /*
97      * Perform a bubble sort of the system initialization objects by
98      * their subsystem (primary key) and order (secondary key).
99      *
100      * Since some things care about execution order, this is the
101      * operation which ensures continued function.
102      */
103     for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
104 	for( xipp = sipp + 1; *xipp; xipp++) {
105 	    if( (*sipp)->subsystem < (*xipp)->subsystem ||
106 		( (*sipp)->subsystem == (*xipp)->subsystem &&
107 		  (*sipp)->order < (*xipp)->order))
108 		continue;	/* skip*/
109 	    save = *sipp;
110 	    *sipp = *xipp;
111 	    *xipp = save;
112 	}
113     }
114 
115 
116     /*
117      * Traverse the (now) ordered list of system initialization tasks.
118      * Perform each task, and continue on to the next task.
119      *
120      * The last item on the list is expected to be the scheduler,
121      * which will not return.
122      */
123     for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
124 	if( (*sipp)->subsystem == SI_SUB_DUMMY)
125 	    continue;	/* skip dummy task(s)*/
126 
127 	switch( (*sipp)->type) {
128 	case SI_TYPE_DEFAULT:
129 	    /* no special processing*/
130 	    (*((*sipp)->func))( (*sipp)->udata);
131 	    break;
132 
133 	case SI_TYPE_KTHREAD:
134 	    /* kernel thread*/
135 	    if (fork(&proc0, NULL, rval))
136 		panic("fork kernel process");
137 	    cpu_set_fork_handler(pfind(rval[0]), (*sipp)->func, (*sipp)->udata);
138 	    break;
139 
140 	default:
141 	    panic( "linker_file_sysinit: unrecognized init type");
142 	}
143     }
144 }
145 
146 int
147 linker_load_file(const char* filename, linker_file_t* result)
148 {
149     linker_class_t lc;
150     linker_file_t lf;
151     int error = 0;
152 
153     lf = linker_find_file_by_name(filename);
154     if (lf) {
155 	KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename));
156 	*result = lf;
157 	lf->refs++;
158 	goto out;
159     }
160 
161     lf = NULL;
162     for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
163 	KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n",
164 		       filename, lc->desc));
165 	if (error = lc->ops->load_file(filename, &lf))
166 	    goto out;
167 	if (lf) {
168 	    linker_file_sysinit(lf);
169 
170 	    *result = lf;
171 	    goto out;
172 	}
173     }
174 
175     error = ENOEXEC;		/* format not recognised */
176 
177 out:
178     return error;
179 }
180 
181 linker_file_t
182 linker_find_file_by_name(const char* filename)
183 {
184     linker_file_t lf = 0;
185 
186     lockmgr(&lock, LK_SHARED, 0, curproc);
187     for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
188 	if (!strcmp(lf->filename, filename))
189 	    break;
190     lockmgr(&lock, LK_RELEASE, 0, curproc);
191 
192     return lf;
193 }
194 
195 linker_file_t
196 linker_find_file_by_id(int fileid)
197 {
198     linker_file_t lf = 0;
199 
200     lockmgr(&lock, LK_SHARED, 0, curproc);
201     for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
202 	if (lf->id == fileid)
203 	    break;
204     lockmgr(&lock, LK_RELEASE, 0, curproc);
205 
206     return lf;
207 }
208 
209 linker_file_t
210 linker_make_file(const char* filename, void* priv, struct linker_file_ops* ops)
211 {
212     linker_file_t lf = 0;
213     int namelen;
214 
215     KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
216     lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
217     namelen = strlen(filename) + 1;
218     lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK);
219     if (!lf)
220 	goto out;
221 
222     lf->refs = 1;
223     lf->userrefs = 0;
224     lf->filename = (char*) (lf + 1);
225     strcpy(lf->filename, filename);
226     lf->id = next_file_id++;
227     lf->ndeps = 0;
228     lf->deps = NULL;
229     STAILQ_INIT(&lf->common);
230     TAILQ_INIT(&lf->modules);
231 
232     lf->priv = priv;
233     lf->ops = ops;
234     TAILQ_INSERT_TAIL(&files, lf, link);
235 
236 out:
237     lockmgr(&lock, LK_RELEASE, 0, curproc);
238     return lf;
239 }
240 
241 int
242 linker_file_unload(linker_file_t file)
243 {
244     module_t mod, next;
245     struct common_symbol* cp;
246     int error = 0;
247     int i;
248 
249     KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", lf->refs));
250     lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
251     if (file->refs == 1) {
252 	KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n"));
253 	/*
254 	 * Inform any modules associated with this file.
255 	 */
256 	for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
257 	    next = module_getfnext(mod);
258 
259 	    /*
260 	     * Give the module a chance to veto the unload.
261 	     */
262 	    if (error = module_unload(mod)) {
263 		KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n",
264 			       mod));
265 		lockmgr(&lock, LK_RELEASE, 0, curproc);
266 		goto out;
267 	    }
268 
269 	    module_release(mod);
270 	}
271     }
272 
273     file->refs--;
274     if (file->refs > 0) {
275 	lockmgr(&lock, LK_RELEASE, 0, curproc);
276 	goto out;
277     }
278 
279     TAILQ_REMOVE(&files, file, link);
280     lockmgr(&lock, LK_RELEASE, 0, curproc);
281 
282     for (i = 0; i < file->ndeps; i++)
283 	linker_file_unload(file->deps[i]);
284     free(file->deps, M_LINKER);
285 
286     for (cp = STAILQ_FIRST(&file->common); cp;
287 	 cp = STAILQ_FIRST(&file->common)) {
288 	STAILQ_REMOVE(&file->common, cp, common_symbol, link);
289 	free(cp, M_LINKER);
290     }
291 
292     file->ops->unload(file);
293     free(file, M_LINKER);
294 
295 out:
296     return error;
297 }
298 
299 int
300 linker_file_add_dependancy(linker_file_t file, linker_file_t dep)
301 {
302     linker_file_t* newdeps;
303 
304     newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*),
305 		     M_LINKER, M_WAITOK);
306     if (newdeps == NULL)
307 	return ENOMEM;
308 
309     if (file->deps) {
310 	bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*));
311 	free(file->deps, M_LINKER);
312     }
313     file->deps = newdeps;
314     file->deps[file->ndeps] = dep;
315     file->ndeps++;
316 
317     return 0;
318 }
319 
320 caddr_t
321 linker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
322 {
323     caddr_t address;
324     size_t size;
325     size_t common_size = 0;
326     int i;
327 
328     KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d",
329 		  file, name, deps));
330 
331     if (file->ops->lookup_symbol(file, name, &address, &size) == 0)
332 	if (address == 0)
333 	    /*
334 	     * For commons, first look them up in the dependancies and
335 	     * only allocate space if not found there.
336 	     */
337 	    common_size = size;
338 	else
339 	    return address;
340 
341     if (deps)
342 	for (i = 0; i < file->ndeps; i++) {
343 	    address = linker_file_lookup_symbol(file->deps[i], name, 0);
344 	    if (address)
345 		return address;
346 	}
347 
348     if (common_size > 0) {
349 	/*
350 	 * This is a common symbol which was not found in the
351 	 * dependancies.  We maintain a simple common symbol table in
352 	 * the file object.
353 	 */
354 	struct common_symbol* cp;
355 
356 	for (cp = STAILQ_FIRST(&file->common); cp;
357 	     cp = STAILQ_NEXT(cp, link))
358 	    if (!strcmp(cp->name, name))
359 		return cp->address;
360 
361 	/*
362 	 * Round the symbol size up to align.
363 	 */
364 	common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
365 	cp = malloc(sizeof(struct common_symbol)
366 		    + common_size
367 		    + strlen(name) + 1,
368 		    M_LINKER, M_WAITOK);
369 	if (!cp)
370 	    return 0;
371 
372 	cp->address = (caddr_t) (cp + 1);
373 	cp->name = cp->address + common_size;
374 	strcpy(cp->name, name);
375 	bzero(cp->address, common_size);
376 	STAILQ_INSERT_TAIL(&file->common, cp, link);
377 
378 	return cp->address;
379     }
380 
381     return 0;
382 }
383 
384 /*
385  * Syscalls.
386  */
387 
388 int
389 kldload(struct proc* p, struct kldload_args* uap, int* retval)
390 {
391     char* filename = NULL;
392     linker_file_t lf;
393     int error = 0;
394 
395     *retval = -1;
396 
397     if (securelevel > 0)
398 	return EPERM;
399 
400     if (error = suser(p->p_ucred, &p->p_acflag))
401 	return error;
402 
403     filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
404     if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))
405 	goto out;
406 
407     if (error = linker_load_file(uap->file, &lf))
408 	goto out;
409 
410     lf->userrefs++;
411     *retval = lf->id;
412 
413 out:
414     if (filename)
415 	free(filename, M_TEMP);
416     return error;
417 }
418 
419 int
420 kldunload(struct proc* p, struct kldunload_args* uap, int* retval)
421 {
422     linker_file_t lf;
423     int error = 0;
424 
425     if (securelevel > 0)
426 	return EPERM;
427 
428     if (error = suser(p->p_ucred, &p->p_acflag))
429 	return error;
430 
431     lf = linker_find_file_by_id(SCARG(uap, fileid));
432     if (lf) {
433 	KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
434 	if (lf->userrefs == 0) {
435 	    printf("linkerunload: attempt to unload file which was not loaded by user\n");
436 	    error = EBUSY;
437 	    goto out;
438 	}
439 	lf->userrefs--;
440 	error = linker_file_unload(lf);
441     } else
442 	error = ENOENT;
443 
444 out:
445     return error;
446 }
447 
448 int
449 kldfind(struct proc* p, struct kldfind_args* uap, int* retval)
450 {
451     char* filename = NULL;
452     linker_file_t lf;
453     int error = 0;
454 
455     *retval = -1;
456 
457     filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
458     if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))
459 	goto out;
460 
461     lf = linker_find_file_by_name(filename);
462     if (lf)
463 	*retval = lf->id;
464     else
465 	error = ENOENT;
466 
467 out:
468     if (filename)
469 	free(filename, M_TEMP);
470     return error;
471 }
472 
473 int
474 kldnext(struct proc* p, struct kldnext_args* uap, int* retval)
475 {
476     linker_file_t lf;
477     int error = 0;
478 
479     if (SCARG(uap, fileid) == 0) {
480 	if (TAILQ_FIRST(&files))
481 	    *retval = TAILQ_FIRST(&files)->id;
482 	else
483 	    *retval = 0;
484 	return 0;
485     }
486 
487     lf = linker_find_file_by_id(SCARG(uap, fileid));
488     if (lf) {
489 	if (TAILQ_NEXT(lf, link))
490 	    *retval = TAILQ_NEXT(lf, link)->id;
491 	else
492 	    *retval = 0;
493     } else
494 	error = ENOENT;
495 
496     return error;
497 }
498 
499 int
500 kldstat(struct proc* p, struct kldstat_args* uap, int* retval)
501 {
502     linker_file_t lf;
503     int error = 0;
504     int version;
505     struct kld_file_stat* stat;
506     int namelen;
507 
508     lf = linker_find_file_by_id(SCARG(uap, fileid));
509     if (!lf) {
510 	error = ENOENT;
511 	goto out;
512     }
513 
514     stat = SCARG(uap, stat);
515 
516     /*
517      * Check the version of the user's structure.
518      */
519     if (error = copyin(&stat->version, &version, sizeof(version)))
520 	goto out;
521     if (version != sizeof(struct kld_file_stat)) {
522 	error = EINVAL;
523 	goto out;
524     }
525 
526     namelen = strlen(lf->filename) + 1;
527     if (namelen > MAXPATHLEN)
528 	namelen = MAXPATHLEN;
529     if (error = copyout(lf->filename, &stat->name[0], namelen))
530 	goto out;
531     if (error = copyout(&lf->refs, &stat->refs, sizeof(int)))
532 	goto out;
533     if (error = copyout(&lf->id, &stat->id, sizeof(int)))
534 	goto out;
535     if (error = copyout(&lf->address, &stat->address, sizeof(caddr_t)))
536 	goto out;
537     if (error = copyout(&lf->size, &stat->size, sizeof(size_t)))
538 	goto out;
539 
540     *retval = 0;
541 
542 out:
543     return error;
544 }
545 
546 int
547 kldfirstmod(struct proc* p, struct kldfirstmod_args* uap, int* retval)
548 {
549     linker_file_t lf;
550     int error = 0;
551 
552     lf = linker_find_file_by_id(SCARG(uap, fileid));
553     if (lf) {
554 	if (TAILQ_FIRST(&lf->modules))
555 	    *retval = module_getid(TAILQ_FIRST(&lf->modules));
556 	else
557 	    *retval = 0;
558     } else
559 	error = ENOENT;
560 
561     return error;
562 }
563