xref: /freebsd/sys/kern/kern_linker.c (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
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: kern_linker.c,v 1.6 1998/01/01 08:56:24 bde Exp $
27  */
28 
29 #include <sys/param.h>
30 #include <sys/kernel.h>
31 #include <sys/systm.h>
32 #include <sys/malloc.h>
33 #include <sys/sysproto.h>
34 #include <sys/sysent.h>
35 #include <sys/proc.h>
36 #include <sys/lock.h>
37 #include <machine/cpu.h>
38 #include <sys/module.h>
39 #include <sys/linker.h>
40 #include <sys/unistd.h>
41 
42 MALLOC_DEFINE(M_LINKER, "kld", "kernel linker");
43 linker_file_t linker_current_file;
44 
45 static struct lock lock;	/* lock for the file list */
46 static linker_class_list_t classes;
47 static linker_file_list_t files;
48 static int next_file_id = 1;
49 
50 static void
51 linker_init(void* arg)
52 {
53     lockinit(&lock, PVM, "klink", 0, 0);
54     TAILQ_INIT(&classes);
55     TAILQ_INIT(&files);
56 }
57 
58 SYSINIT(linker, SI_SUB_KMEM, SI_ORDER_SECOND, linker_init, 0);
59 
60 int
61 linker_add_class(const char* desc, void* priv,
62 		 struct linker_class_ops* ops)
63 {
64     linker_class_t lc;
65 
66     lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT);
67     if (!lc)
68 	return ENOMEM;
69 
70     lc->desc = desc;
71     lc->priv = priv;
72     lc->ops = ops;
73     TAILQ_INSERT_HEAD(&classes, lc, link);
74 
75     return 0;
76 }
77 
78 static void
79 linker_file_sysinit(linker_file_t lf)
80 {
81     struct linker_set* sysinits;
82     struct sysinit** sipp;
83     struct sysinit** xipp;
84     struct sysinit* save;
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 #if !defined(SMP)
135 	    /* kernel thread*/
136 	    if (fork1(&proc0, RFFDG|RFPROC|RFMEM))
137 		panic("fork kernel thread");
138 	    cpu_set_fork_handler(pfind(proc0.p_retval[0]),
139 		(*sipp)->func, (*sipp)->udata);
140 	    break;
141 #endif
142 
143 	case SI_TYPE_KPROCESS:
144 	    /* kernel thread*/
145 	    if (fork1(&proc0, RFFDG|RFPROC))
146 		panic("fork kernel process");
147 	    cpu_set_fork_handler(pfind(proc0.p_retval[0]),
148 		(*sipp)->func, (*sipp)->udata);
149 	    break;
150 
151 	default:
152 	    panic( "linker_file_sysinit: unrecognized init type");
153 	}
154     }
155 }
156 
157 int
158 linker_load_file(const char* filename, linker_file_t* result)
159 {
160     linker_class_t lc;
161     linker_file_t lf;
162     int error = 0;
163 
164     lf = linker_find_file_by_name(filename);
165     if (lf) {
166 	KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename));
167 	*result = lf;
168 	lf->refs++;
169 	goto out;
170     }
171 
172     lf = NULL;
173     for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
174 	KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n",
175 		       filename, lc->desc));
176 	if (error = lc->ops->load_file(filename, &lf))
177 	    goto out;
178 	if (lf) {
179 	    linker_file_sysinit(lf);
180 
181 	    *result = lf;
182 	    goto out;
183 	}
184     }
185 
186     error = ENOEXEC;		/* format not recognised */
187 
188 out:
189     return error;
190 }
191 
192 linker_file_t
193 linker_find_file_by_name(const char* filename)
194 {
195     linker_file_t lf = 0;
196 
197     lockmgr(&lock, LK_SHARED, 0, curproc);
198     for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
199 	if (!strcmp(lf->filename, filename))
200 	    break;
201     lockmgr(&lock, LK_RELEASE, 0, curproc);
202 
203     return lf;
204 }
205 
206 linker_file_t
207 linker_find_file_by_id(int fileid)
208 {
209     linker_file_t lf = 0;
210 
211     lockmgr(&lock, LK_SHARED, 0, curproc);
212     for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
213 	if (lf->id == fileid)
214 	    break;
215     lockmgr(&lock, LK_RELEASE, 0, curproc);
216 
217     return lf;
218 }
219 
220 linker_file_t
221 linker_make_file(const char* filename, void* priv, struct linker_file_ops* ops)
222 {
223     linker_file_t lf = 0;
224     int namelen;
225 
226     KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
227     lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
228     namelen = strlen(filename) + 1;
229     lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK);
230     if (!lf)
231 	goto out;
232 
233     lf->refs = 1;
234     lf->userrefs = 0;
235     lf->filename = (char*) (lf + 1);
236     strcpy(lf->filename, filename);
237     lf->id = next_file_id++;
238     lf->ndeps = 0;
239     lf->deps = NULL;
240     STAILQ_INIT(&lf->common);
241     TAILQ_INIT(&lf->modules);
242 
243     lf->priv = priv;
244     lf->ops = ops;
245     TAILQ_INSERT_TAIL(&files, lf, link);
246 
247 out:
248     lockmgr(&lock, LK_RELEASE, 0, curproc);
249     return lf;
250 }
251 
252 int
253 linker_file_unload(linker_file_t file)
254 {
255     module_t mod, next;
256     struct common_symbol* cp;
257     int error = 0;
258     int i;
259 
260     KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", lf->refs));
261     lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
262     if (file->refs == 1) {
263 	KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n"));
264 	/*
265 	 * Inform any modules associated with this file.
266 	 */
267 	for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
268 	    next = module_getfnext(mod);
269 
270 	    /*
271 	     * Give the module a chance to veto the unload.
272 	     */
273 	    if (error = module_unload(mod)) {
274 		KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n",
275 			       mod));
276 		lockmgr(&lock, LK_RELEASE, 0, curproc);
277 		goto out;
278 	    }
279 
280 	    module_release(mod);
281 	}
282     }
283 
284     file->refs--;
285     if (file->refs > 0) {
286 	lockmgr(&lock, LK_RELEASE, 0, curproc);
287 	goto out;
288     }
289 
290     TAILQ_REMOVE(&files, file, link);
291     lockmgr(&lock, LK_RELEASE, 0, curproc);
292 
293     for (i = 0; i < file->ndeps; i++)
294 	linker_file_unload(file->deps[i]);
295     free(file->deps, M_LINKER);
296 
297     for (cp = STAILQ_FIRST(&file->common); cp;
298 	 cp = STAILQ_FIRST(&file->common)) {
299 	STAILQ_REMOVE(&file->common, cp, common_symbol, link);
300 	free(cp, M_LINKER);
301     }
302 
303     file->ops->unload(file);
304     free(file, M_LINKER);
305 
306 out:
307     return error;
308 }
309 
310 int
311 linker_file_add_dependancy(linker_file_t file, linker_file_t dep)
312 {
313     linker_file_t* newdeps;
314 
315     newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*),
316 		     M_LINKER, M_WAITOK);
317     if (newdeps == NULL)
318 	return ENOMEM;
319 
320     if (file->deps) {
321 	bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*));
322 	free(file->deps, M_LINKER);
323     }
324     file->deps = newdeps;
325     file->deps[file->ndeps] = dep;
326     file->ndeps++;
327 
328     return 0;
329 }
330 
331 caddr_t
332 linker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
333 {
334     linker_sym_t sym;
335     linker_symval_t symval;
336     caddr_t address;
337     size_t common_size = 0;
338     int i;
339 
340     KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d",
341 		  file, name, deps));
342 
343     if (file->ops->lookup_symbol(file, name, &sym) == 0) {
344 	file->ops->symbol_values(file, sym, &symval);
345 	if (symval.value == 0)
346 	    /*
347 	     * For commons, first look them up in the dependancies and
348 	     * only allocate space if not found there.
349 	     */
350 	    common_size = symval.size;
351 	else
352 	    return symval.value;
353     }
354 
355     if (deps)
356 	for (i = 0; i < file->ndeps; i++) {
357 	    address = linker_file_lookup_symbol(file->deps[i], name, 0);
358 	    if (address)
359 		return address;
360 	}
361 
362     if (common_size > 0) {
363 	/*
364 	 * This is a common symbol which was not found in the
365 	 * dependancies.  We maintain a simple common symbol table in
366 	 * the file object.
367 	 */
368 	struct common_symbol* cp;
369 
370 	for (cp = STAILQ_FIRST(&file->common); cp;
371 	     cp = STAILQ_NEXT(cp, link))
372 	    if (!strcmp(cp->name, name))
373 		return cp->address;
374 
375 	/*
376 	 * Round the symbol size up to align.
377 	 */
378 	common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
379 	cp = malloc(sizeof(struct common_symbol)
380 		    + common_size
381 		    + strlen(name) + 1,
382 		    M_LINKER, M_WAITOK);
383 	if (!cp)
384 	    return 0;
385 
386 	cp->address = (caddr_t) (cp + 1);
387 	cp->name = cp->address + common_size;
388 	strcpy(cp->name, name);
389 	bzero(cp->address, common_size);
390 	STAILQ_INSERT_TAIL(&file->common, cp, link);
391 
392 	return cp->address;
393     }
394 
395     return 0;
396 }
397 
398 /*
399  * Syscalls.
400  */
401 
402 int
403 kldload(struct proc* p, struct kldload_args* uap)
404 {
405     char* filename = NULL;
406     linker_file_t lf;
407     int error = 0;
408 
409     p->p_retval[0] = -1;
410 
411     if (securelevel > 0)
412 	return EPERM;
413 
414     if (error = suser(p->p_ucred, &p->p_acflag))
415 	return error;
416 
417     filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
418     if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))
419 	goto out;
420 
421     if (error = linker_load_file(uap->file, &lf))
422 	goto out;
423 
424     lf->userrefs++;
425     p->p_retval[0] = lf->id;
426 
427 out:
428     if (filename)
429 	free(filename, M_TEMP);
430     return error;
431 }
432 
433 int
434 kldunload(struct proc* p, struct kldunload_args* uap)
435 {
436     linker_file_t lf;
437     int error = 0;
438 
439     if (securelevel > 0)
440 	return EPERM;
441 
442     if (error = suser(p->p_ucred, &p->p_acflag))
443 	return error;
444 
445     lf = linker_find_file_by_id(SCARG(uap, fileid));
446     if (lf) {
447 	KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
448 	if (lf->userrefs == 0) {
449 	    printf("linkerunload: attempt to unload file which was not loaded by user\n");
450 	    error = EBUSY;
451 	    goto out;
452 	}
453 	lf->userrefs--;
454 	error = linker_file_unload(lf);
455     } else
456 	error = ENOENT;
457 
458 out:
459     return error;
460 }
461 
462 int
463 kldfind(struct proc* p, struct kldfind_args* uap)
464 {
465     char* filename = NULL;
466     linker_file_t lf;
467     int error = 0;
468 
469     p->p_retval[0] = -1;
470 
471     filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
472     if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))
473 	goto out;
474 
475     lf = linker_find_file_by_name(filename);
476     if (lf)
477 	p->p_retval[0] = lf->id;
478     else
479 	error = ENOENT;
480 
481 out:
482     if (filename)
483 	free(filename, M_TEMP);
484     return error;
485 }
486 
487 int
488 kldnext(struct proc* p, struct kldnext_args* uap)
489 {
490     linker_file_t lf;
491     int error = 0;
492 
493     if (SCARG(uap, fileid) == 0) {
494 	if (TAILQ_FIRST(&files))
495 	    p->p_retval[0] = TAILQ_FIRST(&files)->id;
496 	else
497 	    p->p_retval[0] = 0;
498 	return 0;
499     }
500 
501     lf = linker_find_file_by_id(SCARG(uap, fileid));
502     if (lf) {
503 	if (TAILQ_NEXT(lf, link))
504 	    p->p_retval[0] = TAILQ_NEXT(lf, link)->id;
505 	else
506 	    p->p_retval[0] = 0;
507     } else
508 	error = ENOENT;
509 
510     return error;
511 }
512 
513 int
514 kldstat(struct proc* p, struct kldstat_args* uap)
515 {
516     linker_file_t lf;
517     int error = 0;
518     int version;
519     struct kld_file_stat* stat;
520     int namelen;
521 
522     lf = linker_find_file_by_id(SCARG(uap, fileid));
523     if (!lf) {
524 	error = ENOENT;
525 	goto out;
526     }
527 
528     stat = SCARG(uap, stat);
529 
530     /*
531      * Check the version of the user's structure.
532      */
533     if (error = copyin(&stat->version, &version, sizeof(version)))
534 	goto out;
535     if (version != sizeof(struct kld_file_stat)) {
536 	error = EINVAL;
537 	goto out;
538     }
539 
540     namelen = strlen(lf->filename) + 1;
541     if (namelen > MAXPATHLEN)
542 	namelen = MAXPATHLEN;
543     if (error = copyout(lf->filename, &stat->name[0], namelen))
544 	goto out;
545     if (error = copyout(&lf->refs, &stat->refs, sizeof(int)))
546 	goto out;
547     if (error = copyout(&lf->id, &stat->id, sizeof(int)))
548 	goto out;
549     if (error = copyout(&lf->address, &stat->address, sizeof(caddr_t)))
550 	goto out;
551     if (error = copyout(&lf->size, &stat->size, sizeof(size_t)))
552 	goto out;
553 
554     p->p_retval[0] = 0;
555 
556 out:
557     return error;
558 }
559 
560 int
561 kldfirstmod(struct proc* p, struct kldfirstmod_args* uap)
562 {
563     linker_file_t lf;
564     int error = 0;
565 
566     lf = linker_find_file_by_id(SCARG(uap, fileid));
567     if (lf) {
568 	if (TAILQ_FIRST(&lf->modules))
569 	    p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules));
570 	else
571 	    p->p_retval[0] = 0;
572     } else
573 	error = ENOENT;
574 
575     return error;
576 }
577