netbsd32_module.c revision 1.10
1/* $NetBSD: netbsd32_module.c,v 1.10 2019/03/01 11:06:56 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_module.c,v 1.10 2019/03/01 11:06:56 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/netbsd32/netbsd32.h> 41#include <compat/netbsd32/netbsd32_syscall.h> 42#include <compat/netbsd32/netbsd32_syscallargs.h> 43#include <compat/netbsd32/netbsd32_conv.h> 44 45static int 46modctl32_handle_stat(struct netbsd32_iovec *iov, void *arg) 47{ 48 int ms_cnt; 49 modstat_t *ms, *mso; 50 size_t ms_len; 51 char *req, *reqo; 52 size_t req_len; 53 char *out_p; 54 size_t out_s; 55 56 modinfo_t *mi; 57 module_t *mod; 58 vaddr_t addr; 59 size_t size; 60 size_t used; 61 int off; 62 int error; 63 bool stataddr; 64 65 /* If not privileged, don't expose kernel addresses. */ 66 error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE, 67 0, (void *)(uintptr_t)MODCTL_STAT, NULL, NULL); 68 stataddr = (error == 0); 69 70 kernconfig_lock(); 71 ms_cnt = 0; 72 req_len = 1; 73 74 /* 75 * Count up the number of modstat_t needed, and total size of 76 * require_module lists on both active and built-in lists 77 */ 78 TAILQ_FOREACH(mod, &module_list, mod_chain) { 79 ms_cnt++; 80 mi = mod->mod_info; 81 if (mi->mi_required != NULL) { 82 req_len += strlen(mi->mi_required) + 1; 83 } 84 } 85 TAILQ_FOREACH(mod, &module_builtins, mod_chain) { 86 ms_cnt++; 87 mi = mod->mod_info; 88 if (mi->mi_required != NULL) { 89 req_len += strlen(mi->mi_required) + 1; 90 } 91 } 92 93 /* Allocate internal buffers to hold all the output data */ 94 ms_len = ms_cnt * sizeof(modstat_t); 95 ms = kmem_zalloc(ms_len, KM_SLEEP); 96 req = kmem_zalloc(req_len, KM_SLEEP); 97 98 mso = ms; 99 reqo = req++; 100 off = 1; 101 102 /* 103 * Load data into our internal buffers for both active and 104 * build-in module lists 105 */ 106 TAILQ_FOREACH(mod, &module_list, mod_chain) { 107 mi = mod->mod_info; 108 strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name)); 109 if (mi->mi_required != NULL) { 110 ms->ms_reqoffset = off; 111 used = strlcpy(req, mi->mi_required, req_len - off); 112 KASSERTMSG(used < req_len - off, "reqlist grew!"); 113 off = used + 1; 114 req += used + 1; 115 } else 116 ms->ms_reqoffset = 0; 117 if (mod->mod_kobj != NULL && stataddr) { 118 kobj_stat(mod->mod_kobj, &addr, &size); 119 ms->ms_addr = addr; 120 ms->ms_size = size; 121 } 122 ms->ms_class = mi->mi_class; 123 ms->ms_refcnt = mod->mod_refcnt; 124 ms->ms_source = mod->mod_source; 125 ms->ms_flags = mod->mod_flags; 126 ms++; 127 } 128 TAILQ_FOREACH(mod, &module_builtins, mod_chain) { 129 mi = mod->mod_info; 130 strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name)); 131 if (mi->mi_required != NULL) { 132 ms->ms_reqoffset = off; 133 used = strlcpy(req, mi->mi_required, req_len - off); 134 KASSERTMSG(used < req_len - off, "reqlist grew!"); 135 off += used + 1; 136 req += used + 1; 137 } else 138 ms->ms_reqoffset = 0; 139 if (mod->mod_kobj != NULL && stataddr) { 140 kobj_stat(mod->mod_kobj, &addr, &size); 141 ms->ms_addr = addr; 142 ms->ms_size = size; 143 } 144 ms->ms_class = mi->mi_class; 145 ms->ms_refcnt = -1; 146 KASSERT(mod->mod_source == MODULE_SOURCE_KERNEL); 147 ms->ms_source = mod->mod_source; 148 ms++; 149 } 150 kernconfig_unlock(); 151 152 /* 153 * Now copyout our internal buffers back to userland 154 */ 155 out_p = NETBSD32PTR64(iov->iov_base); 156 out_s = iov->iov_len; 157 size = sizeof(ms_cnt); 158 159 /* Copy out the count of modstat_t */ 160 if (out_s) { 161 size = uimin(sizeof(ms_cnt), out_s); 162 error = copyout(&ms_cnt, out_p, size); 163 out_p += size; 164 out_s -= size; 165 } 166 /* Copy out the modstat_t array */ 167 if (out_s && error == 0) { 168 size = uimin(ms_len, out_s); 169 error = copyout(mso, out_p, size); 170 out_p += size; 171 out_s -= size; 172 } 173 /* Copy out the "required" strings */ 174 if (out_s && error == 0) { 175 size = uimin(req_len, out_s); 176 error = copyout(reqo, out_p, size); 177 out_p += size; 178 out_s -= size; 179 } 180 kmem_free(mso, ms_len); 181 kmem_free(reqo, req_len); 182 183 /* Finally, update the userland copy of the iovec's length */ 184 if (error == 0) { 185 iov->iov_len = ms_len + req_len + sizeof(ms_cnt); 186 error = copyout(iov, arg, sizeof(*iov)); 187 } 188 189 return error; 190} 191 192int 193compat32_80_modctl_compat_stub(struct lwp *lwp, 194 const struct netbsd32_modctl_args *uap, register_t *result) 195{ 196 197 return EPASSTHROUGH; 198} 199 200int 201netbsd32_modctl(struct lwp *lwp, const struct netbsd32_modctl_args *uap, 202 register_t *result) 203{ 204 /* { 205 syscallarg(int) cmd; 206 syscallarg(netbsd32_voidp) arg; 207 } */ 208 char buf[MAXMODNAME]; 209 struct netbsd32_iovec iov; 210 struct netbsd32_modctl_load ml; 211 int error; 212 void *arg; 213#ifdef MODULAR 214 uintptr_t loadtype; 215#endif 216 217 arg = SCARG_P32(uap, arg); 218 219 MODULE_HOOK_CALL(compat32_80_modctl_hook, (lwp, uap, result), 220 enosys(), error); 221 if (error != EPASSTHROUGH && error != ENOSYS) 222 return error; 223 224 switch (SCARG(uap, cmd)) { 225 case MODCTL_LOAD: 226 error = copyin(arg, &ml, sizeof(ml)); 227 if (error != 0) 228 break; 229 error = handle_modctl_load(NETBSD32PTR64(ml.ml_filename), 230 ml.ml_flags, NETBSD32PTR64(ml.ml_props), ml.ml_propslen); 231 break; 232 233 case MODCTL_UNLOAD: 234 error = copyinstr(arg, buf, sizeof(buf), NULL); 235 if (error == 0) { 236 error = module_unload(buf); 237 } 238 break; 239 240 case MODCTL_STAT: 241 error = copyin(arg, &iov, sizeof(iov)); 242 if (error != 0) { 243 break; 244 } 245 error = modctl32_handle_stat(&iov, arg); 246 break; 247 248 case MODCTL_EXISTS: 249#ifndef MODULAR 250 error = ENOSYS; 251#else 252 loadtype = (uintptr_t)arg; 253 switch (loadtype) { /* 0 = modload, 1 = autoload */ 254 case 0: /* FALLTHROUGH */ 255 case 1: 256 error = kauth_authorize_system(kauth_cred_get(), 257 KAUTH_SYSTEM_MODULE, 0, 258 (void *)(uintptr_t)MODCTL_LOAD, 259 (void *)loadtype, NULL); 260 break; 261 262 default: 263 error = EINVAL; 264 break; 265 } 266#endif 267 break; 268 269 default: 270 error = EINVAL; 271 break; 272 } 273 274 return error; 275} 276