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