1 1.11 andvar /* $NetBSD: netbsd32_module.c,v 1.11 2022/05/24 06:20:04 andvar Exp $ */ 2 1.1 martin 3 1.1 martin /*- 4 1.1 martin * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 1.1 martin * All rights reserved. 6 1.1 martin * 7 1.1 martin * This code is derived from software developed for The NetBSD Foundation. 8 1.1 martin * 9 1.1 martin * Redistribution and use in source and binary forms, with or without 10 1.1 martin * modification, are permitted provided that the following conditions 11 1.1 martin * are met: 12 1.1 martin * 1. Redistributions of source code must retain the above copyright 13 1.1 martin * notice, this list of conditions and the following disclaimer. 14 1.1 martin * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 martin * notice, this list of conditions and the following disclaimer in the 16 1.1 martin * documentation and/or other materials provided with the distribution. 17 1.1 martin * 18 1.1 martin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 1.1 martin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 1.1 martin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 1.1 martin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 1.1 martin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 1.1 martin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 1.1 martin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 1.1 martin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 1.1 martin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 1.1 martin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 1.1 martin * POSSIBILITY OF SUCH DAMAGE. 29 1.1 martin */ 30 1.1 martin 31 1.1 martin #include <sys/cdefs.h> 32 1.11 andvar __KERNEL_RCSID(0, "$NetBSD: netbsd32_module.c,v 1.11 2022/05/24 06:20:04 andvar Exp $"); 33 1.1 martin 34 1.1 martin #include <sys/param.h> 35 1.1 martin #include <sys/dirent.h> 36 1.2 msaitoh #include <sys/kauth.h> 37 1.1 martin #include <sys/module.h> 38 1.1 martin #include <sys/kobj.h> 39 1.1 martin 40 1.1 martin #include <compat/netbsd32/netbsd32.h> 41 1.1 martin #include <compat/netbsd32/netbsd32_syscall.h> 42 1.1 martin #include <compat/netbsd32/netbsd32_syscallargs.h> 43 1.1 martin #include <compat/netbsd32/netbsd32_conv.h> 44 1.1 martin 45 1.3 maxv static int 46 1.3 maxv modctl32_handle_stat(struct netbsd32_iovec *iov, void *arg) 47 1.3 maxv { 48 1.8 pgoyette int ms_cnt; 49 1.3 maxv modstat_t *ms, *mso; 50 1.8 pgoyette size_t ms_len; 51 1.8 pgoyette char *req, *reqo; 52 1.8 pgoyette size_t req_len; 53 1.8 pgoyette char *out_p; 54 1.8 pgoyette size_t out_s; 55 1.8 pgoyette 56 1.3 maxv modinfo_t *mi; 57 1.3 maxv module_t *mod; 58 1.3 maxv vaddr_t addr; 59 1.3 maxv size_t size; 60 1.8 pgoyette size_t used; 61 1.8 pgoyette int off; 62 1.3 maxv int error; 63 1.6 maxv bool stataddr; 64 1.6 maxv 65 1.6 maxv /* If not privileged, don't expose kernel addresses. */ 66 1.6 maxv error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE, 67 1.6 maxv 0, (void *)(uintptr_t)MODCTL_STAT, NULL, NULL); 68 1.6 maxv stataddr = (error == 0); 69 1.3 maxv 70 1.3 maxv kernconfig_lock(); 71 1.8 pgoyette ms_cnt = 0; 72 1.8 pgoyette req_len = 1; 73 1.8 pgoyette 74 1.8 pgoyette /* 75 1.8 pgoyette * Count up the number of modstat_t needed, and total size of 76 1.8 pgoyette * require_module lists on both active and built-in lists 77 1.8 pgoyette */ 78 1.8 pgoyette TAILQ_FOREACH(mod, &module_list, mod_chain) { 79 1.8 pgoyette ms_cnt++; 80 1.8 pgoyette mi = mod->mod_info; 81 1.8 pgoyette if (mi->mi_required != NULL) { 82 1.8 pgoyette req_len += strlen(mi->mi_required) + 1; 83 1.8 pgoyette } 84 1.8 pgoyette } 85 1.8 pgoyette TAILQ_FOREACH(mod, &module_builtins, mod_chain) { 86 1.8 pgoyette ms_cnt++; 87 1.8 pgoyette mi = mod->mod_info; 88 1.8 pgoyette if (mi->mi_required != NULL) { 89 1.8 pgoyette req_len += strlen(mi->mi_required) + 1; 90 1.8 pgoyette } 91 1.8 pgoyette } 92 1.8 pgoyette 93 1.8 pgoyette /* Allocate internal buffers to hold all the output data */ 94 1.8 pgoyette ms_len = ms_cnt * sizeof(modstat_t); 95 1.8 pgoyette ms = kmem_zalloc(ms_len, KM_SLEEP); 96 1.8 pgoyette req = kmem_zalloc(req_len, KM_SLEEP); 97 1.8 pgoyette 98 1.8 pgoyette mso = ms; 99 1.8 pgoyette reqo = req++; 100 1.8 pgoyette off = 1; 101 1.8 pgoyette 102 1.8 pgoyette /* 103 1.8 pgoyette * Load data into our internal buffers for both active and 104 1.11 andvar * built-in module lists 105 1.8 pgoyette */ 106 1.3 maxv TAILQ_FOREACH(mod, &module_list, mod_chain) { 107 1.3 maxv mi = mod->mod_info; 108 1.3 maxv strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name)); 109 1.3 maxv if (mi->mi_required != NULL) { 110 1.8 pgoyette ms->ms_reqoffset = off; 111 1.8 pgoyette used = strlcpy(req, mi->mi_required, req_len - off); 112 1.8 pgoyette KASSERTMSG(used < req_len - off, "reqlist grew!"); 113 1.8 pgoyette off = used + 1; 114 1.8 pgoyette req += used + 1; 115 1.8 pgoyette } else 116 1.8 pgoyette ms->ms_reqoffset = 0; 117 1.6 maxv if (mod->mod_kobj != NULL && stataddr) { 118 1.3 maxv kobj_stat(mod->mod_kobj, &addr, &size); 119 1.3 maxv ms->ms_addr = addr; 120 1.3 maxv ms->ms_size = size; 121 1.3 maxv } 122 1.3 maxv ms->ms_class = mi->mi_class; 123 1.3 maxv ms->ms_refcnt = mod->mod_refcnt; 124 1.3 maxv ms->ms_source = mod->mod_source; 125 1.4 maxv ms->ms_flags = mod->mod_flags; 126 1.3 maxv ms++; 127 1.3 maxv } 128 1.3 maxv TAILQ_FOREACH(mod, &module_builtins, mod_chain) { 129 1.3 maxv mi = mod->mod_info; 130 1.3 maxv strlcpy(ms->ms_name, mi->mi_name, sizeof(ms->ms_name)); 131 1.3 maxv if (mi->mi_required != NULL) { 132 1.8 pgoyette ms->ms_reqoffset = off; 133 1.8 pgoyette used = strlcpy(req, mi->mi_required, req_len - off); 134 1.8 pgoyette KASSERTMSG(used < req_len - off, "reqlist grew!"); 135 1.8 pgoyette off += used + 1; 136 1.8 pgoyette req += used + 1; 137 1.8 pgoyette } else 138 1.8 pgoyette ms->ms_reqoffset = 0; 139 1.6 maxv if (mod->mod_kobj != NULL && stataddr) { 140 1.3 maxv kobj_stat(mod->mod_kobj, &addr, &size); 141 1.3 maxv ms->ms_addr = addr; 142 1.3 maxv ms->ms_size = size; 143 1.3 maxv } 144 1.3 maxv ms->ms_class = mi->mi_class; 145 1.3 maxv ms->ms_refcnt = -1; 146 1.3 maxv KASSERT(mod->mod_source == MODULE_SOURCE_KERNEL); 147 1.3 maxv ms->ms_source = mod->mod_source; 148 1.3 maxv ms++; 149 1.3 maxv } 150 1.3 maxv kernconfig_unlock(); 151 1.8 pgoyette 152 1.8 pgoyette /* 153 1.8 pgoyette * Now copyout our internal buffers back to userland 154 1.8 pgoyette */ 155 1.8 pgoyette out_p = NETBSD32PTR64(iov->iov_base); 156 1.8 pgoyette out_s = iov->iov_len; 157 1.8 pgoyette size = sizeof(ms_cnt); 158 1.8 pgoyette 159 1.8 pgoyette /* Copy out the count of modstat_t */ 160 1.8 pgoyette if (out_s) { 161 1.8 pgoyette size = uimin(sizeof(ms_cnt), out_s); 162 1.8 pgoyette error = copyout(&ms_cnt, out_p, size); 163 1.8 pgoyette out_p += size; 164 1.8 pgoyette out_s -= size; 165 1.8 pgoyette } 166 1.8 pgoyette /* Copy out the modstat_t array */ 167 1.8 pgoyette if (out_s && error == 0) { 168 1.8 pgoyette size = uimin(ms_len, out_s); 169 1.8 pgoyette error = copyout(mso, out_p, size); 170 1.8 pgoyette out_p += size; 171 1.8 pgoyette out_s -= size; 172 1.8 pgoyette } 173 1.8 pgoyette /* Copy out the "required" strings */ 174 1.8 pgoyette if (out_s && error == 0) { 175 1.8 pgoyette size = uimin(req_len, out_s); 176 1.8 pgoyette error = copyout(reqo, out_p, size); 177 1.8 pgoyette out_p += size; 178 1.8 pgoyette out_s -= size; 179 1.8 pgoyette } 180 1.8 pgoyette kmem_free(mso, ms_len); 181 1.8 pgoyette kmem_free(reqo, req_len); 182 1.8 pgoyette 183 1.8 pgoyette /* Finally, update the userland copy of the iovec's length */ 184 1.3 maxv if (error == 0) { 185 1.8 pgoyette iov->iov_len = ms_len + req_len + sizeof(ms_cnt); 186 1.3 maxv error = copyout(iov, arg, sizeof(*iov)); 187 1.3 maxv } 188 1.3 maxv 189 1.3 maxv return error; 190 1.3 maxv } 191 1.3 maxv 192 1.1 martin int 193 1.8 pgoyette compat32_80_modctl_compat_stub(struct lwp *lwp, 194 1.8 pgoyette const struct netbsd32_modctl_args *uap, register_t *result) 195 1.8 pgoyette { 196 1.8 pgoyette 197 1.8 pgoyette return EPASSTHROUGH; 198 1.8 pgoyette } 199 1.8 pgoyette 200 1.8 pgoyette int 201 1.1 martin netbsd32_modctl(struct lwp *lwp, const struct netbsd32_modctl_args *uap, 202 1.1 martin register_t *result) 203 1.1 martin { 204 1.1 martin /* { 205 1.1 martin syscallarg(int) cmd; 206 1.1 martin syscallarg(netbsd32_voidp) arg; 207 1.1 martin } */ 208 1.1 martin char buf[MAXMODNAME]; 209 1.1 martin struct netbsd32_iovec iov; 210 1.1 martin struct netbsd32_modctl_load ml; 211 1.1 martin int error; 212 1.1 martin void *arg; 213 1.1 martin #ifdef MODULAR 214 1.1 martin uintptr_t loadtype; 215 1.1 martin #endif 216 1.1 martin 217 1.1 martin arg = SCARG_P32(uap, arg); 218 1.1 martin 219 1.10 pgoyette MODULE_HOOK_CALL(compat32_80_modctl_hook, (lwp, uap, result), 220 1.8 pgoyette enosys(), error); 221 1.8 pgoyette if (error != EPASSTHROUGH && error != ENOSYS) 222 1.8 pgoyette return error; 223 1.8 pgoyette 224 1.1 martin switch (SCARG(uap, cmd)) { 225 1.1 martin case MODCTL_LOAD: 226 1.1 martin error = copyin(arg, &ml, sizeof(ml)); 227 1.1 martin if (error != 0) 228 1.1 martin break; 229 1.1 martin error = handle_modctl_load(NETBSD32PTR64(ml.ml_filename), 230 1.1 martin ml.ml_flags, NETBSD32PTR64(ml.ml_props), ml.ml_propslen); 231 1.1 martin break; 232 1.1 martin 233 1.1 martin case MODCTL_UNLOAD: 234 1.1 martin error = copyinstr(arg, buf, sizeof(buf), NULL); 235 1.1 martin if (error == 0) { 236 1.1 martin error = module_unload(buf); 237 1.1 martin } 238 1.1 martin break; 239 1.1 martin 240 1.1 martin case MODCTL_STAT: 241 1.1 martin error = copyin(arg, &iov, sizeof(iov)); 242 1.1 martin if (error != 0) { 243 1.1 martin break; 244 1.1 martin } 245 1.3 maxv error = modctl32_handle_stat(&iov, arg); 246 1.1 martin break; 247 1.1 martin 248 1.1 martin case MODCTL_EXISTS: 249 1.1 martin #ifndef MODULAR 250 1.1 martin error = ENOSYS; 251 1.1 martin #else 252 1.1 martin loadtype = (uintptr_t)arg; 253 1.1 martin switch (loadtype) { /* 0 = modload, 1 = autoload */ 254 1.1 martin case 0: /* FALLTHROUGH */ 255 1.1 martin case 1: 256 1.1 martin error = kauth_authorize_system(kauth_cred_get(), 257 1.1 martin KAUTH_SYSTEM_MODULE, 0, 258 1.1 martin (void *)(uintptr_t)MODCTL_LOAD, 259 1.1 martin (void *)loadtype, NULL); 260 1.1 martin break; 261 1.1 martin 262 1.1 martin default: 263 1.1 martin error = EINVAL; 264 1.1 martin break; 265 1.1 martin } 266 1.1 martin #endif 267 1.1 martin break; 268 1.1 martin 269 1.1 martin default: 270 1.1 martin error = EINVAL; 271 1.1 martin break; 272 1.1 martin } 273 1.1 martin 274 1.1 martin return error; 275 1.1 martin } 276