1 /* $NetBSD: veriexec.c,v 1.1 2015/12/09 18:25:32 maxv 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.1 2015/12/09 18:25:32 maxv 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.h> 47 #define DEVPORT_DEVICE struct device 48 49 #include <prop/proplib.h> 50 51 void veriexecattach(device_t, device_t, void *); 52 static dev_type_open(veriexecopen); 53 static dev_type_close(veriexecclose); 54 static dev_type_ioctl(veriexecioctl); 55 56 struct veriexec_softc { 57 DEVPORT_DEVICE veriexec_dev; 58 }; 59 60 const struct cdevsw veriexec_cdevsw = { 61 .d_open = veriexecopen, 62 .d_close = veriexecclose, 63 .d_read = noread, 64 .d_write = nowrite, 65 .d_ioctl = veriexecioctl, 66 .d_stop = nostop, 67 .d_tty = notty, 68 .d_poll = nopoll, 69 .d_mmap = nommap, 70 .d_discard = nodiscard, 71 .d_kqfilter = nokqfilter, 72 .d_flag = D_OTHER, 73 }; 74 75 /* count of number of times device is open (we really only allow one open) */ 76 static unsigned int veriexec_dev_usage = 0; 77 78 void 79 veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self, void *aux) 80 { 81 veriexec_dev_usage = 0; 82 } 83 84 static int 85 veriexecopen(dev_t dev, int flags, int fmt, struct lwp *l) 86 { 87 if (kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_VERIEXEC, 88 KAUTH_REQ_SYSTEM_VERIEXEC_ACCESS, NULL, NULL, NULL)) 89 return (EPERM); 90 91 if (veriexec_dev_usage > 0) 92 return(EBUSY); 93 94 veriexec_dev_usage++; 95 return (0); 96 } 97 98 static int 99 veriexecclose(dev_t dev, int flags, int fmt, struct lwp *l) 100 { 101 if (veriexec_dev_usage > 0) 102 veriexec_dev_usage--; 103 return (0); 104 } 105 106 static int 107 veriexec_delete(prop_dictionary_t dict, struct lwp *l) 108 { 109 struct vnode *vp; 110 const char *file; 111 int error; 112 113 if (!prop_dictionary_get_cstring_nocopy(dict, "file", &file)) 114 return (EINVAL); 115 116 error = namei_simple_kernel(file, NSM_FOLLOW_NOEMULROOT, &vp); 117 if (error) 118 return (error); 119 120 /* XXX this should be done differently... */ 121 if (vp->v_type == VREG) 122 error = veriexec_file_delete(l, vp); 123 else if (vp->v_type == VDIR) 124 error = veriexec_table_delete(l, vp->v_mount); 125 126 vrele(vp); 127 128 return (error); 129 } 130 131 static int 132 veriexec_query(prop_dictionary_t dict, prop_dictionary_t rdict, struct lwp *l) 133 { 134 struct vnode *vp; 135 const char *file; 136 int error; 137 138 if (!prop_dictionary_get_cstring_nocopy(dict, "file", &file)) 139 return (EINVAL); 140 141 error = namei_simple_kernel(file, NSM_FOLLOW_NOEMULROOT, &vp); 142 if (error) 143 return (error); 144 145 error = veriexec_convert(vp, rdict); 146 147 vrele(vp); 148 149 return (error); 150 } 151 152 int 153 veriexecioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 154 { 155 struct plistref *plistref; 156 prop_dictionary_t dict; 157 int error = 0; 158 159 switch (cmd) { 160 case VERIEXEC_TABLESIZE: 161 case VERIEXEC_LOAD: 162 case VERIEXEC_DELETE: 163 case VERIEXEC_FLUSH: 164 if (!(flags & FWRITE)) 165 return (EPERM); 166 167 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_VERIEXEC, 168 KAUTH_REQ_SYSTEM_VERIEXEC_MODIFY, KAUTH_ARG(cmd), NULL, 169 NULL); 170 if (error) 171 return error; 172 173 break; 174 175 case VERIEXEC_QUERY: 176 case VERIEXEC_DUMP: 177 if (!(flags & FREAD)) 178 return (EPERM); 179 180 break; 181 182 default: 183 /* Invalid operation. */ 184 return (ENODEV); 185 } 186 187 plistref = (struct plistref *)data; 188 189 switch (cmd) { 190 case VERIEXEC_TABLESIZE: 191 /* Do nothing. Kept for binary compatibility. */ 192 break; 193 194 case VERIEXEC_LOAD: 195 error = prop_dictionary_copyin_ioctl(plistref, cmd, &dict); 196 if (error) 197 break; 198 199 error = veriexec_file_add(l, dict); 200 prop_object_release(dict); 201 break; 202 203 case VERIEXEC_DELETE: 204 error = prop_dictionary_copyin_ioctl(plistref, cmd, &dict); 205 if (error) 206 break; 207 208 error = veriexec_delete(dict, l); 209 prop_object_release(dict); 210 break; 211 212 case VERIEXEC_QUERY: { 213 prop_dictionary_t rdict; 214 215 error = prop_dictionary_copyin_ioctl(plistref, cmd, &dict); 216 if (error) 217 return (error); 218 219 rdict = prop_dictionary_create(); 220 if (rdict == NULL) { 221 prop_object_release(dict); 222 error = ENOMEM; 223 break; 224 } 225 226 error = veriexec_query(dict, rdict, l); 227 if (error == 0) { 228 error = prop_dictionary_copyout_ioctl(plistref, cmd, 229 rdict); 230 } 231 232 prop_object_release(rdict); 233 prop_object_release(dict); 234 235 break; 236 } 237 238 case VERIEXEC_DUMP: { 239 prop_array_t rarray; 240 241 rarray = prop_array_create(); 242 if (rarray == NULL) { 243 error = ENOMEM; 244 break; 245 } 246 247 error = veriexec_dump(l, rarray); 248 if (error == 0) { 249 error = prop_array_copyout_ioctl(plistref, cmd, 250 rarray); 251 } 252 253 prop_object_release(rarray); 254 255 break; 256 } 257 258 case VERIEXEC_FLUSH: 259 error = veriexec_flush(l); 260 break; 261 262 default: 263 /* Invalid operation. */ 264 error = ENODEV; 265 break; 266 } 267 268 return (error); 269 } 270 271