xref: /netbsd-src/sys/compat/common/kern_mod_80.c (revision 8a031a1d1e0aac23d43015c71ae6350b917c8347)
1*8a031a1dSpgoyette /*	$NetBSD: kern_mod_80.c,v 1.6 2019/12/12 02:15:42 pgoyette Exp $	*/
2d91f98a8Spgoyette 
3d91f98a8Spgoyette /*-
4d91f98a8Spgoyette  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5d91f98a8Spgoyette  * All rights reserved.
6d91f98a8Spgoyette  *
7d91f98a8Spgoyette  * Redistribution and use in source and binary forms, with or without
8d91f98a8Spgoyette  * modification, are permitted provided that the following conditions
9d91f98a8Spgoyette  * are met:
10d91f98a8Spgoyette  * 1. Redistributions of source code must retain the above copyright
11d91f98a8Spgoyette  *    notice, this list of conditions and the following disclaimer.
12d91f98a8Spgoyette  * 2. Redistributions in binary form must reproduce the above copyright
13d91f98a8Spgoyette  *    notice, this list of conditions and the following disclaimer in the
14d91f98a8Spgoyette  *    documentation and/or other materials provided with the distribution.
15d91f98a8Spgoyette  *
16d91f98a8Spgoyette  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17d91f98a8Spgoyette  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18d91f98a8Spgoyette  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19d91f98a8Spgoyette  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20d91f98a8Spgoyette  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21d91f98a8Spgoyette  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22d91f98a8Spgoyette  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23d91f98a8Spgoyette  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24d91f98a8Spgoyette  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25d91f98a8Spgoyette  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26d91f98a8Spgoyette  * POSSIBILITY OF SUCH DAMAGE.
27d91f98a8Spgoyette  */
28d91f98a8Spgoyette 
29d91f98a8Spgoyette /*
30d91f98a8Spgoyette  * System calls relating to loadable modules.
31d91f98a8Spgoyette  */
32d91f98a8Spgoyette 
33d91f98a8Spgoyette #include <sys/cdefs.h>
34*8a031a1dSpgoyette __KERNEL_RCSID(0, "$NetBSD: kern_mod_80.c,v 1.6 2019/12/12 02:15:42 pgoyette Exp $");
35d91f98a8Spgoyette 
36d91f98a8Spgoyette #ifdef _KERNEL_OPT
37d91f98a8Spgoyette #include "opt_compat_netbsd.h"
38d91f98a8Spgoyette #include "opt_modular.h"
39d91f98a8Spgoyette #endif
40d91f98a8Spgoyette 
41d91f98a8Spgoyette #include <sys/param.h>
42d91f98a8Spgoyette #include <sys/systm.h>
43d91f98a8Spgoyette #include <sys/proc.h>
44d91f98a8Spgoyette #include <sys/namei.h>
45d91f98a8Spgoyette #include <sys/kauth.h>
46d91f98a8Spgoyette #include <sys/kmem.h>
47d91f98a8Spgoyette #include <sys/kobj.h>
48d91f98a8Spgoyette #include <sys/module.h>
49d91f98a8Spgoyette #include <sys/syscall.h>
50d91f98a8Spgoyette #include <sys/syscallargs.h>
51d91f98a8Spgoyette #include <sys/compat_stub.h>
52fd56c8ffSpgoyette 
53fd56c8ffSpgoyette #include <compat/sys/module.h>
54d91f98a8Spgoyette 
55d91f98a8Spgoyette #include <compat/common/compat_mod.h>
56d91f98a8Spgoyette 
57d91f98a8Spgoyette static int
compat_80_modstat(int cmd,struct iovec * iov,void * arg)58d91f98a8Spgoyette compat_80_modstat(int cmd, struct iovec *iov, void *arg)
59d91f98a8Spgoyette {
60d91f98a8Spgoyette 	omodstat_t *oms, *omso;
61d91f98a8Spgoyette 	modinfo_t *mi;
62d91f98a8Spgoyette 	module_t *mod;
63d91f98a8Spgoyette 	vaddr_t addr;
64d91f98a8Spgoyette 	size_t size;
65d91f98a8Spgoyette 	size_t omslen;
66d91f98a8Spgoyette 	size_t used;
67d91f98a8Spgoyette 	int error;
68d91f98a8Spgoyette 	int omscnt;
69d91f98a8Spgoyette 	bool stataddr;
70d91f98a8Spgoyette 	const char *suffix = "...";
71d91f98a8Spgoyette 
72d91f98a8Spgoyette 	if (cmd != MODCTL_OSTAT)
73d91f98a8Spgoyette 		return EINVAL;
74d91f98a8Spgoyette 
75d91f98a8Spgoyette 	error = copyin(arg, iov, sizeof(*iov));
76d91f98a8Spgoyette 	if (error != 0) {
77d91f98a8Spgoyette 		return error;
78d91f98a8Spgoyette 	}
79d91f98a8Spgoyette 
80d91f98a8Spgoyette 	/* If not privileged, don't expose kernel addresses. */
81d91f98a8Spgoyette 	error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE,
82d91f98a8Spgoyette 	    0, (void *)(uintptr_t)MODCTL_STAT, NULL, NULL);
83d91f98a8Spgoyette 	stataddr = (error == 0);
84d91f98a8Spgoyette 
85d91f98a8Spgoyette 	kernconfig_lock();
86d91f98a8Spgoyette 	omscnt = 0;
87d91f98a8Spgoyette 	TAILQ_FOREACH(mod, &module_list, mod_chain) {
88d91f98a8Spgoyette 		omscnt++;
89d91f98a8Spgoyette 		mi = mod->mod_info;
90d91f98a8Spgoyette 	}
91d91f98a8Spgoyette 	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
92d91f98a8Spgoyette 		omscnt++;
93d91f98a8Spgoyette 		mi = mod->mod_info;
94d91f98a8Spgoyette 	}
95d91f98a8Spgoyette 	omslen = omscnt * sizeof(omodstat_t);
96d91f98a8Spgoyette 	omso = kmem_zalloc(omslen, KM_SLEEP);
97d91f98a8Spgoyette 	oms = omso;
98d91f98a8Spgoyette 	TAILQ_FOREACH(mod, &module_list, mod_chain) {
99d91f98a8Spgoyette 		mi = mod->mod_info;
100d91f98a8Spgoyette 		strlcpy(oms->oms_name, mi->mi_name, sizeof(oms->oms_name));
101d91f98a8Spgoyette 		if (mi->mi_required != NULL) {
102d91f98a8Spgoyette 			used = strlcpy(oms->oms_required, mi->mi_required,
103d91f98a8Spgoyette 			    sizeof(oms->oms_required));
104d91f98a8Spgoyette 			if (used >= sizeof(oms->oms_required)) {
105d91f98a8Spgoyette 				oms->oms_required[sizeof(oms->oms_required) -
106d91f98a8Spgoyette 				    strlen(suffix) - 1] = '\0';
107d91f98a8Spgoyette 				strlcat(oms->oms_required, suffix,
108d91f98a8Spgoyette 				    sizeof(oms->oms_required));
109d91f98a8Spgoyette 			}
110d91f98a8Spgoyette 		}
111d91f98a8Spgoyette 		if (mod->mod_kobj != NULL && stataddr) {
112d91f98a8Spgoyette 			kobj_stat(mod->mod_kobj, &addr, &size);
113d91f98a8Spgoyette 			oms->oms_addr = addr;
114d91f98a8Spgoyette 			oms->oms_size = size;
115d91f98a8Spgoyette 		}
116d91f98a8Spgoyette 		oms->oms_class = mi->mi_class;
117d91f98a8Spgoyette 		oms->oms_refcnt = mod->mod_refcnt;
118d91f98a8Spgoyette 		oms->oms_source = mod->mod_source;
119d91f98a8Spgoyette 		oms->oms_flags = mod->mod_flags;
120d91f98a8Spgoyette 		oms++;
121d91f98a8Spgoyette 	}
122d91f98a8Spgoyette 	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
123d91f98a8Spgoyette 		mi = mod->mod_info;
124d91f98a8Spgoyette 		strlcpy(oms->oms_name, mi->mi_name, sizeof(oms->oms_name));
125d91f98a8Spgoyette 		if (mi->mi_required != NULL) {
126d91f98a8Spgoyette 			used = strlcpy(oms->oms_required, mi->mi_required,
127d91f98a8Spgoyette 			    sizeof(oms->oms_required));
128d91f98a8Spgoyette 			if (used >= sizeof(oms->oms_required)) {
129d91f98a8Spgoyette 				oms->oms_required[sizeof(oms->oms_required) -
130d91f98a8Spgoyette 				    strlen(suffix) - 1] = '\0';
131d91f98a8Spgoyette 				strlcat(oms->oms_required, suffix,
132d91f98a8Spgoyette 				    sizeof(oms->oms_required));
133d91f98a8Spgoyette 			}
134d91f98a8Spgoyette 		}
135d91f98a8Spgoyette 		if (mod->mod_kobj != NULL && stataddr) {
136d91f98a8Spgoyette 			kobj_stat(mod->mod_kobj, &addr, &size);
137d91f98a8Spgoyette 			oms->oms_addr = addr;
138d91f98a8Spgoyette 			oms->oms_size = size;
139d91f98a8Spgoyette 		}
140d91f98a8Spgoyette 		oms->oms_class = mi->mi_class;
141d91f98a8Spgoyette 		oms->oms_refcnt = -1;
142d91f98a8Spgoyette 		KASSERT(mod->mod_source == MODULE_SOURCE_KERNEL);
143d91f98a8Spgoyette 		oms->oms_source = mod->mod_source;
144d91f98a8Spgoyette 		oms++;
145d91f98a8Spgoyette 	}
146d91f98a8Spgoyette 	kernconfig_unlock();
147d91f98a8Spgoyette 	error = copyout(omso, iov->iov_base, uimin(omslen, iov->iov_len));
148d91f98a8Spgoyette 	kmem_free(omso, omslen);
149d91f98a8Spgoyette 	if (error == 0) {
150d91f98a8Spgoyette 		iov->iov_len = omslen;
151d91f98a8Spgoyette 		error = copyout(iov, arg, sizeof(*iov));
152d91f98a8Spgoyette 	}
153d91f98a8Spgoyette 
154d91f98a8Spgoyette 	return error;
155d91f98a8Spgoyette }
156d91f98a8Spgoyette 
157d91f98a8Spgoyette void
kern_mod_80_init(void)158d91f98a8Spgoyette kern_mod_80_init(void)
159d91f98a8Spgoyette {
160d91f98a8Spgoyette 
161*8a031a1dSpgoyette 	MODULE_HOOK_SET(compat_modstat_80_hook, compat_80_modstat);
162d91f98a8Spgoyette }
163d91f98a8Spgoyette 
164d91f98a8Spgoyette void
kern_mod_80_fini(void)165d91f98a8Spgoyette kern_mod_80_fini(void)
166d91f98a8Spgoyette {
167d91f98a8Spgoyette 
1688c2f80f1Spgoyette 	MODULE_HOOK_UNSET(compat_modstat_80_hook);
169d91f98a8Spgoyette }
170