1/*	$NetBSD: netbsd32_compat_80.c,v 1.8 2023/07/29 13:57:28 pgoyette Exp $	*/
2
3/*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software developed for The NetBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__KERNEL_RCSID(0, "$NetBSD: netbsd32_compat_80.c,v 1.8 2023/07/29 13:57:28 pgoyette Exp $");
33
34#include <sys/param.h>
35#include <sys/dirent.h>
36#include <sys/kauth.h>
37#include <sys/module.h>
38#include <sys/kobj.h>
39
40#include <compat/sys/siginfo.h>
41
42#include <compat/sys/module.h>
43
44#include <compat/netbsd32/netbsd32.h>
45#include <compat/netbsd32/netbsd32_syscall.h>
46#include <compat/netbsd32/netbsd32_syscallargs.h>
47#include <compat/netbsd32/netbsd32_conv.h>
48
49int netbsd32_80_modctl(struct lwp *, const struct netbsd32_modctl_args *,
50	register_t *);
51
52static int
53modctl32_handle_ostat(int cmd, struct netbsd32_iovec *iov, void *arg)
54{
55	omodstat_t *oms, *omso;
56	modinfo_t *mi;
57	module_t *mod;
58	vaddr_t addr;
59	size_t size;
60	size_t omslen;
61	size_t used;
62	int error;
63	int omscnt;
64	bool stataddr;
65	const char *suffix = "...";
66
67	if (cmd != MODCTL_OSTAT)
68		return EINVAL;
69
70	/* If not privileged, don't expose kernel addresses. */
71	error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE,
72	    0, (void *)(uintptr_t)MODCTL_STAT, NULL, NULL);
73	stataddr = (error == 0);
74
75	kernconfig_lock();
76	omscnt = 0;
77	TAILQ_FOREACH(mod, &module_list, mod_chain) {
78		omscnt++;
79		mi = mod->mod_info;
80	}
81	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
82		omscnt++;
83		mi = mod->mod_info;
84	}
85	omslen = omscnt * sizeof(omodstat_t);
86	omso = kmem_zalloc(omslen, KM_SLEEP);
87	oms = omso;
88	TAILQ_FOREACH(mod, &module_list, mod_chain) {
89		mi = mod->mod_info;
90		strlcpy(oms->oms_name, mi->mi_name, sizeof(oms->oms_name));
91		if (mi->mi_required != NULL) {
92			used = strlcpy(oms->oms_required, mi->mi_required,
93			    sizeof(oms->oms_required));
94			if (used >= sizeof(oms->oms_required)) {
95				oms->oms_required[sizeof(oms->oms_required) -
96				    strlen(suffix) - 1] = '\0';
97				strlcat(oms->oms_required, suffix,
98				    sizeof(oms->oms_required));
99                        }
100		}
101		if (mod->mod_kobj != NULL && stataddr) {
102			kobj_stat(mod->mod_kobj, &addr, &size);
103			oms->oms_addr = addr;
104			oms->oms_size = size;
105		}
106		oms->oms_class = mi->mi_class;
107		oms->oms_refcnt = mod->mod_refcnt;
108		oms->oms_source = mod->mod_source;
109		oms->oms_flags = mod->mod_flags;
110		oms++;
111	}
112	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
113		mi = mod->mod_info;
114		strlcpy(oms->oms_name, mi->mi_name, sizeof(oms->oms_name));
115		if (mi->mi_required != NULL) {
116			used = strlcpy(oms->oms_required, mi->mi_required,
117			    sizeof(oms->oms_required));
118			if (used >= sizeof(oms->oms_required)) {
119				oms->oms_required[sizeof(oms->oms_required) -
120				    strlen(suffix) - 1] = '\0';
121				strlcat(oms->oms_required, suffix,
122				    sizeof(oms->oms_required));
123                        }
124		}
125		if (mod->mod_kobj != NULL && stataddr) {
126			kobj_stat(mod->mod_kobj, &addr, &size);
127			oms->oms_addr = addr;
128			oms->oms_size = size;
129		}
130		oms->oms_class = mi->mi_class;
131		oms->oms_refcnt = -1;
132		KASSERT(mod->mod_source == MODULE_SOURCE_KERNEL);
133		oms->oms_source = mod->mod_source;
134		oms++;
135	}
136	kernconfig_unlock();
137	error = copyout(omso, NETBSD32PTR64(iov->iov_base),
138	    uimin(omslen - sizeof(modstat_t), iov->iov_len));
139	kmem_free(omso, omslen);
140	if (error == 0) {
141		iov->iov_len = omslen - sizeof(modstat_t);
142		error = copyout(iov, arg, sizeof(*iov));
143	}
144
145	return error;
146}
147
148int
149netbsd32_80_modctl(struct lwp *lwp, const struct netbsd32_modctl_args *uap,
150	register_t *result)
151{
152	/* {
153		syscallarg(int) cmd;
154		syscallarg(netbsd32_voidp) arg;
155	} */
156	struct netbsd32_iovec iov;
157	int error;
158	void *arg;
159
160	arg = SCARG_P32(uap, arg);
161
162	switch (SCARG(uap, cmd)) {
163	case MODCTL_OSTAT:
164		error = copyin(arg, &iov, sizeof(iov));
165		if (error != 0) {
166			break;
167		}
168		error = modctl32_handle_ostat(SCARG(uap, cmd), &iov, arg);
169		break;
170	default:
171		error = EPASSTHROUGH;
172		break;
173	}
174
175	return error;
176}
177
178MODULE(MODULE_CLASS_EXEC, compat_netbsd32_80, "compat_netbsd32_90,compat_80");
179
180static int
181compat_netbsd32_80_modcmd(modcmd_t cmd, void *arg)
182{
183
184	switch (cmd) {
185	case MODULE_CMD_INIT:
186		MODULE_HOOK_SET(compat32_80_modctl_hook, netbsd32_80_modctl);
187		return 0;
188
189	case MODULE_CMD_FINI:
190		MODULE_HOOK_UNSET(compat32_80_modctl_hook);
191		return 0;
192
193	default:
194		return ENOTTY;
195	}
196}
197