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