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