Home | History | Annotate | Line # | Download | only in dev
      1 /*	$NetBSD: veriexec.c,v 1.3 2022/02/12 02:40:48 riastradh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2005, 2006 Elad Efrat <elad (at) NetBSD.org>
      5  * Copyright (c) 2005, 2006 Brett Lymn <blymn (at) NetBSD.org>
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of the authors may not be used to endorse or promote products
     17  *    derived from this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: veriexec.c,v 1.3 2022/02/12 02:40:48 riastradh Exp $");
     33 
     34 #include <sys/param.h>
     35 #include <sys/errno.h>
     36 #include <sys/conf.h>
     37 #include <sys/vnode.h>
     38 #include <sys/fcntl.h>
     39 #include <sys/namei.h>
     40 #include <sys/verified_exec.h>
     41 #include <sys/kauth.h>
     42 #include <sys/syslog.h>
     43 #include <sys/proc.h>
     44 
     45 #include <sys/ioctl.h>
     46 #include <sys/device_if.h>
     47 
     48 #include <prop/proplib.h>
     49 
     50 void veriexecattach(device_t, device_t, void *);
     51 static dev_type_open(veriexecopen);
     52 static dev_type_close(veriexecclose);
     53 static dev_type_ioctl(veriexecioctl);
     54 
     55 const struct cdevsw veriexec_cdevsw = {
     56 	.d_open = veriexecopen,
     57 	.d_close = veriexecclose,
     58 	.d_read = noread,
     59 	.d_write = nowrite,
     60 	.d_ioctl = veriexecioctl,
     61 	.d_stop = nostop,
     62 	.d_tty = notty,
     63 	.d_poll = nopoll,
     64 	.d_mmap = nommap,
     65 	.d_discard = nodiscard,
     66 	.d_kqfilter = nokqfilter,
     67 	.d_flag = D_OTHER,
     68 };
     69 
     70 /* count of number of times device is open (we really only allow one open) */
     71 static unsigned int veriexec_dev_usage = 0;
     72 
     73 void
     74 veriexecattach(device_t parent, device_t self, void *aux)
     75 {
     76 	veriexec_dev_usage = 0;
     77 }
     78 
     79 static int
     80 veriexecopen(dev_t dev, int flags, int fmt, struct lwp *l)
     81 {
     82 	if (kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_VERIEXEC,
     83 	    KAUTH_REQ_SYSTEM_VERIEXEC_ACCESS, NULL, NULL, NULL))
     84 		return (EPERM);
     85 
     86 	if (veriexec_dev_usage > 0)
     87 		return(EBUSY);
     88 
     89 	veriexec_dev_usage++;
     90 	return (0);
     91 }
     92 
     93 static int
     94 veriexecclose(dev_t dev, int flags, int fmt, struct lwp *l)
     95 {
     96 	if (veriexec_dev_usage > 0)
     97 		veriexec_dev_usage--;
     98 	return (0);
     99 }
    100 
    101 static int
    102 veriexec_delete(prop_dictionary_t dict, struct lwp *l)
    103 {
    104 	struct vnode *vp;
    105 	const char *file;
    106 	int error;
    107 
    108 	if (!prop_dictionary_get_string(dict, "file", &file))
    109 		return (EINVAL);
    110 
    111 	error = namei_simple_kernel(file, NSM_FOLLOW_NOEMULROOT, &vp);
    112 	if (error)
    113 		return (error);
    114 
    115 	/* XXX this should be done differently... */
    116 	if (vp->v_type == VREG)
    117 		error = veriexec_file_delete(l, vp);
    118 	else if (vp->v_type == VDIR)
    119 		error = veriexec_table_delete(l, vp->v_mount);
    120 
    121 	vrele(vp);
    122 
    123 	return (error);
    124 }
    125 
    126 static int
    127 veriexec_query(prop_dictionary_t dict, prop_dictionary_t rdict, struct lwp *l)
    128 {
    129 	struct vnode *vp;
    130 	const char *file;
    131 	int error;
    132 
    133 	if (!prop_dictionary_get_string(dict, "file", &file))
    134 		return (EINVAL);
    135 
    136 	error = namei_simple_kernel(file, NSM_FOLLOW_NOEMULROOT, &vp);
    137 	if (error)
    138 		return (error);
    139 
    140 	error = veriexec_convert(vp, rdict);
    141 
    142 	vrele(vp);
    143 
    144 	return (error);
    145 }
    146 
    147 int
    148 veriexecioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
    149 {
    150 	struct plistref *plistref;
    151 	prop_dictionary_t dict;
    152 	int error = 0;
    153 
    154 	switch (cmd) {
    155 	case VERIEXEC_TABLESIZE:
    156 	case VERIEXEC_LOAD:
    157 	case VERIEXEC_DELETE:
    158 	case VERIEXEC_FLUSH:
    159 		if (!(flags & FWRITE))
    160 			return (EPERM);
    161 
    162 		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_VERIEXEC,
    163 		    KAUTH_REQ_SYSTEM_VERIEXEC_MODIFY, KAUTH_ARG(cmd), NULL,
    164 		    NULL);
    165 		if (error)
    166 			return error;
    167 
    168 		break;
    169 
    170 	case VERIEXEC_QUERY:
    171 	case VERIEXEC_DUMP:
    172 		if (!(flags & FREAD))
    173 			return (EPERM);
    174 
    175 		break;
    176 
    177 	default:
    178 		/* Invalid operation. */
    179 		return (ENODEV);
    180 	}
    181 
    182 	plistref = (struct plistref *)data;
    183 
    184 	switch (cmd) {
    185 	case VERIEXEC_TABLESIZE:
    186 		/* Do nothing. Kept for binary compatibility. */
    187 		break;
    188 
    189 	case VERIEXEC_LOAD:
    190 		error = prop_dictionary_copyin_ioctl(plistref, cmd, &dict);
    191 		if (error)
    192 			break;
    193 
    194 		error = veriexec_file_add(l, dict);
    195 		prop_object_release(dict);
    196 		break;
    197 
    198 	case VERIEXEC_DELETE:
    199 		error = prop_dictionary_copyin_ioctl(plistref, cmd, &dict);
    200 		if (error)
    201 			break;
    202 
    203 		error = veriexec_delete(dict, l);
    204 		prop_object_release(dict);
    205 		break;
    206 
    207 	case VERIEXEC_QUERY: {
    208 		prop_dictionary_t rdict;
    209 
    210 		error = prop_dictionary_copyin_ioctl(plistref, cmd, &dict);
    211 		if (error)
    212 			return (error);
    213 
    214 		rdict = prop_dictionary_create();
    215 		if (rdict == NULL) {
    216 			prop_object_release(dict);
    217 			error = ENOMEM;
    218 			break;
    219 		}
    220 
    221 		error = veriexec_query(dict, rdict, l);
    222 		if (error == 0) {
    223 			error = prop_dictionary_copyout_ioctl(plistref, cmd,
    224 			    rdict);
    225 		}
    226 
    227 		prop_object_release(rdict);
    228 		prop_object_release(dict);
    229 
    230 		break;
    231 		}
    232 
    233 	case VERIEXEC_DUMP: {
    234 		prop_array_t rarray;
    235 
    236 		rarray = prop_array_create();
    237 		if (rarray == NULL) {
    238 			error = ENOMEM;
    239 			break;
    240 		}
    241 
    242 		error = veriexec_dump(l, rarray);
    243 		if (error == 0) {
    244 			error = prop_array_copyout_ioctl(plistref, cmd,
    245 			    rarray);
    246 		}
    247 
    248 		prop_object_release(rarray);
    249 
    250 		break;
    251 		}
    252 
    253 	case VERIEXEC_FLUSH:
    254 		error = veriexec_flush(l);
    255 		break;
    256 
    257 	default:
    258 		/* Invalid operation. */
    259 		error = ENODEV;
    260 		break;
    261 	}
    262 
    263 	return (error);
    264 }
    265 
    266