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@NetBSD.org> 5 * Copyright (c) 2005, 2006 Brett Lymn <blymn@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 50void veriexecattach(device_t, device_t, void *); 51static dev_type_open(veriexecopen); 52static dev_type_close(veriexecclose); 53static dev_type_ioctl(veriexecioctl); 54 55const 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) */ 71static unsigned int veriexec_dev_usage = 0; 72 73void 74veriexecattach(device_t parent, device_t self, void *aux) 75{ 76 veriexec_dev_usage = 0; 77} 78 79static int 80veriexecopen(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 93static int 94veriexecclose(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 101static int 102veriexec_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 126static int 127veriexec_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 147int 148veriexecioctl(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