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