xref: /netbsd-src/sys/kern/sys_module.c (revision 3d82d542363f52d2fa17a8343368d25fa3413106)
1*3d82d542Srumble /*	$NetBSD: sys_module.c,v 1.3 2008/01/17 22:30:54 rumble Exp $	*/
2bbc79e58Sad 
3bbc79e58Sad /*-
4bbc79e58Sad  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5bbc79e58Sad  * All rights reserved.
6bbc79e58Sad  *
7bbc79e58Sad  * Redistribution and use in source and binary forms, with or without
8bbc79e58Sad  * modification, are permitted provided that the following conditions
9bbc79e58Sad  * are met:
10bbc79e58Sad  * 1. Redistributions of source code must retain the above copyright
11bbc79e58Sad  *    notice, this list of conditions and the following disclaimer.
12bbc79e58Sad  * 2. Redistributions in binary form must reproduce the above copyright
13bbc79e58Sad  *    notice, this list of conditions and the following disclaimer in the
14bbc79e58Sad  *    documentation and/or other materials provided with the distribution.
15bbc79e58Sad  * 3. All advertising materials mentioning features or use of this software
16bbc79e58Sad  *    must display the following acknowledgement:
17bbc79e58Sad  *	This product includes software developed by the NetBSD
18bbc79e58Sad  *	Foundation, Inc. and its contributors.
19bbc79e58Sad  * 4. Neither the name of The NetBSD Foundation nor the names of its
20bbc79e58Sad  *    contributors may be used to endorse or promote products derived
21bbc79e58Sad  *    from this software without specific prior written permission.
22bbc79e58Sad  *
23bbc79e58Sad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24bbc79e58Sad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25bbc79e58Sad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26bbc79e58Sad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27bbc79e58Sad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28bbc79e58Sad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29bbc79e58Sad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30bbc79e58Sad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31bbc79e58Sad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32bbc79e58Sad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33bbc79e58Sad  * POSSIBILITY OF SUCH DAMAGE.
34bbc79e58Sad  */
35bbc79e58Sad 
36bbc79e58Sad /*
37bbc79e58Sad  * System calls relating to loadable modules.
38bbc79e58Sad  */
39bbc79e58Sad 
40bbc79e58Sad #include <sys/cdefs.h>
41*3d82d542Srumble __KERNEL_RCSID(0, "$NetBSD: sys_module.c,v 1.3 2008/01/17 22:30:54 rumble Exp $");
42bbc79e58Sad 
43bbc79e58Sad #include <sys/param.h>
44bbc79e58Sad #include <sys/systm.h>
45bbc79e58Sad #include <sys/proc.h>
46*3d82d542Srumble #include <sys/namei.h>
47bbc79e58Sad #include <sys/kauth.h>
48bbc79e58Sad #include <sys/kobj.h>
49bbc79e58Sad #include <sys/kmem.h>
50bbc79e58Sad #include <sys/module.h>
51bbc79e58Sad #include <sys/kauth.h>
52bbc79e58Sad #include <sys/syscall.h>
53bbc79e58Sad #include <sys/syscallargs.h>
54bbc79e58Sad 
55bbc79e58Sad int
56bbc79e58Sad sys_modctl(struct lwp *l, const struct sys_modctl_args *uap,
57bbc79e58Sad 	   register_t *retval)
58bbc79e58Sad {
59bbc79e58Sad 	/* {
60bbc79e58Sad 		syscallarg(int)		cmd;
61bbc79e58Sad 		syscallarg(void *)	arg;
62bbc79e58Sad 	} */
63bbc79e58Sad 	char buf[MAXMODNAME];
64bbc79e58Sad 	size_t mslen;
65bbc79e58Sad 	module_t *mod;
66bbc79e58Sad 	modinfo_t *mi;
67bbc79e58Sad 	modstat_t *ms, *mso;
68bbc79e58Sad 	vaddr_t addr;
69bbc79e58Sad 	size_t size;
70bbc79e58Sad 	struct iovec iov;
71bbc79e58Sad 	int error;
72bbc79e58Sad 	void *arg;
73*3d82d542Srumble 	char *path;
74bbc79e58Sad 
75bbc79e58Sad 	arg = SCARG(uap, arg);
76bbc79e58Sad 
77bbc79e58Sad 	switch (SCARG(uap, cmd)) {
78bbc79e58Sad 	case MODCTL_LOAD:
79bbc79e58Sad 	case MODCTL_FORCELOAD:
80bbc79e58Sad 	case MODCTL_UNLOAD:
81bbc79e58Sad 		/* Authorize. */
82bbc79e58Sad 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MODULE,
831ada21e1Sad 		    0, (void *)(uintptr_t)SCARG(uap, cmd), NULL, NULL);
84bbc79e58Sad 		if (error != 0) {
85bbc79e58Sad 			return error;
86bbc79e58Sad 		}
87bbc79e58Sad 		break;
88bbc79e58Sad 	default:
89bbc79e58Sad 		break;
90bbc79e58Sad 	}
91bbc79e58Sad 
92bbc79e58Sad 	switch (SCARG(uap, cmd)) {
93bbc79e58Sad 	case MODCTL_FORCELOAD:
94bbc79e58Sad 	case MODCTL_LOAD:
95*3d82d542Srumble 		path = PNBUF_GET();
96*3d82d542Srumble 		error = copyinstr(arg, path, MAXPATHLEN, NULL);
97bbc79e58Sad 		if (error == 0) {
98*3d82d542Srumble 			error = module_load(path,
99bbc79e58Sad 			    SCARG(uap, cmd) == MODCTL_FORCELOAD);
100bbc79e58Sad 		}
101*3d82d542Srumble 		PNBUF_PUT(path);
102bbc79e58Sad 		break;
103bbc79e58Sad 
104bbc79e58Sad 	case MODCTL_UNLOAD:
105*3d82d542Srumble 		error = copyinstr(arg, buf, sizeof(buf), NULL);
106bbc79e58Sad 		if (error == 0) {
107bbc79e58Sad 			error = module_unload(buf);
108bbc79e58Sad 		}
109bbc79e58Sad 		break;
110bbc79e58Sad 
111bbc79e58Sad 	case MODCTL_STAT:
112bbc79e58Sad 		error = copyin(arg, &iov, sizeof(iov));
113bbc79e58Sad 		if (error != 0) {
114bbc79e58Sad 			break;
115bbc79e58Sad 		}
116bbc79e58Sad 		mutex_enter(&module_lock);
117bbc79e58Sad 		mslen = (module_count + 1) * sizeof(modstat_t);
118bbc79e58Sad 		mso = kmem_zalloc(mslen, KM_SLEEP);
119bbc79e58Sad 		if (mso == NULL) {
120bbc79e58Sad 			mutex_exit(&module_lock);
121bbc79e58Sad 			return ENOMEM;
122bbc79e58Sad 		}
123bbc79e58Sad 		ms = mso;
124bbc79e58Sad 		TAILQ_FOREACH(mod, &module_list, mod_chain) {
125bbc79e58Sad 			mi = mod->mod_info;
126bbc79e58Sad 			strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name));
127bbc79e58Sad 			if (mi->mi_required != NULL) {
128bbc79e58Sad 				strlcpy(ms->ms_required, mi->mi_required,
129bbc79e58Sad 				    sizeof(ms->ms_required));
130bbc79e58Sad 			}
131bbc79e58Sad 			if (mod->mod_kobj != NULL) {
132bbc79e58Sad 				kobj_stat(mod->mod_kobj, &addr, &size);
133bbc79e58Sad 				ms->ms_addr = addr;
134bbc79e58Sad 				ms->ms_size = size;
135bbc79e58Sad 			}
136bbc79e58Sad 			ms->ms_class = mi->mi_class;
137bbc79e58Sad 			ms->ms_refcnt = mod->mod_refcnt;
138bbc79e58Sad 			ms->ms_source = mod->mod_source;
139bbc79e58Sad 			ms++;
140bbc79e58Sad 		}
141bbc79e58Sad 		mutex_exit(&module_lock);
142bbc79e58Sad 		error = copyout(mso, iov.iov_base,
143bbc79e58Sad 		    min(mslen - sizeof(modstat_t), iov.iov_len));
144bbc79e58Sad 		kmem_free(mso, mslen);
145bbc79e58Sad 		if (error == 0) {
146bbc79e58Sad 			iov.iov_len = mslen - sizeof(modstat_t);
147bbc79e58Sad 			error = copyout(&iov, arg, sizeof(iov));
148bbc79e58Sad 		}
149bbc79e58Sad 		break;
150bbc79e58Sad 
151bbc79e58Sad 	default:
152bbc79e58Sad 		error = EINVAL;
153bbc79e58Sad 		break;
154bbc79e58Sad 	}
155bbc79e58Sad 
156bbc79e58Sad 	return error;
157bbc79e58Sad }
158