1 /* 2 * $FreeBSD$ 3 * 4 * Copyright (c) 2011, 2012, 2013, 2015, 2016, Juniper Networks, Inc. 5 * All rights reserved. 6 * 7 * Originally derived from: 8 * $NetBSD: kern_verifiedexec.c,v 1.7 2003/11/18 13:13:03 martin Exp $ 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 #include "opt_mac.h" 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/imgact.h> 39 #include <sys/jail.h> 40 #include <sys/kernel.h> 41 #include <sys/lock.h> 42 #include <sys/malloc.h> 43 #include <sys/mount.h> 44 #include <sys/mutex.h> 45 #include <sys/proc.h> 46 #include <sys/sbuf.h> 47 #include <sys/syslog.h> 48 #include <sys/vnode.h> 49 50 #include "mac_veriexec.h" 51 #include "mac_veriexec_internal.h" 52 53 /** 54 * @var fpops_list 55 * @internal 56 * @brief Fingerprint operations list 57 * 58 * This is essentially the list of fingerprint modules currently loaded 59 */ 60 static LIST_HEAD(fpopshead, mac_veriexec_fpops) fpops_list; 61 62 static int mac_veriexec_late; 63 64 static int sysctl_mac_veriexec_algorithms(SYSCTL_HANDLER_ARGS); 65 66 SYSCTL_PROC(_security_mac_veriexec, OID_AUTO, algorithms, 67 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 68 0, 0, sysctl_mac_veriexec_algorithms, "A", 69 "Verified execution supported hashing algorithms"); 70 71 static int 72 sysctl_mac_veriexec_algorithms(SYSCTL_HANDLER_ARGS) 73 { 74 struct sbuf sb; 75 struct mac_veriexec_fpops *fpops; 76 int algorithms, error; 77 78 algorithms = 0; 79 sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND); 80 LIST_FOREACH(fpops, &fpops_list, entries) { 81 if (algorithms++) 82 sbuf_printf(&sb, " "); 83 sbuf_printf(&sb, "%s", fpops->type); 84 } 85 sbuf_finish(&sb); 86 error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb)); 87 sbuf_delete(&sb); 88 return (error); 89 } 90 91 /** 92 * @internal 93 * @brief Consistently identify file encountering errors 94 * 95 * @param imgp image params to display 96 * @param td calling thread 97 * @param msg message to display 98 * 99 * @return String form of the information stored in @p imgp 100 */ 101 static void 102 identify_error (struct image_params *imgp, struct thread *td, const char *msg) 103 { 104 struct proc *parent; 105 pid_t ppid, gppid; 106 107 parent = imgp->proc->p_pptr; 108 ppid = (parent != NULL) ? parent->p_pid : 0; 109 gppid = (parent != NULL && parent->p_pptr != NULL) ? 110 parent->p_pptr->p_pid : 0; 111 112 log(LOG_ERR, MAC_VERIEXEC_FULLNAME ": %s (file=%s fsid=%ju fileid=%ju " 113 "gen=%lu uid=%u pid=%u ppid=%u gppid=%u)", msg, 114 (imgp->args != NULL) ? imgp->args->fname : "", 115 (uintmax_t)imgp->attr->va_fsid, (uintmax_t)imgp->attr->va_fileid, 116 imgp->attr->va_gen, td->td_ucred->cr_ruid, imgp->proc->p_pid, 117 ppid, gppid); 118 } 119 120 /** 121 * @internal 122 * @brief Check the fingerprint type for the given file and evaluate the 123 * fingerprint for that file. 124 * 125 * It is assumed that @p fingerprint has sufficient storage to hold the 126 * resulting fingerprint string. 127 * 128 * @param vp vnode to check 129 * @param ip file info from the meta-data store 130 * @param td calling thread 131 * @param file_size size of the file to read 132 * @param fingerprint resulting fingerprint 133 * 134 * @return 0 on success, otherwise an error code. 135 */ 136 static int 137 evaluate_fingerprint(struct vnode *vp, struct mac_veriexec_file_info *ip, 138 struct thread *td, off_t file_size, unsigned char *fingerprint) 139 { 140 uint8_t *filebuf; 141 void *ctx; 142 off_t offset; 143 size_t count, nread, resid; 144 int error = EINVAL; 145 146 filebuf = malloc(PAGE_SIZE, M_VERIEXEC, M_WAITOK); 147 ctx = malloc(ip->ops->context_size, M_VERIEXEC, M_WAITOK); 148 149 (ip->ops->init)(ctx); 150 for (offset = 0; offset < file_size; offset += nread) { 151 if ((offset + PAGE_SIZE) > file_size) 152 count = file_size - offset; 153 else 154 count = PAGE_SIZE; 155 156 error = vn_rdwr_inchunks(UIO_READ, vp, filebuf, count, offset, 157 UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, &resid, 158 td); 159 if (error) 160 goto failed; 161 162 nread = count - resid; 163 (ip->ops->update)(ctx, filebuf, nread); 164 } 165 (ip->ops->final)(fingerprint, ctx); 166 167 #ifdef DEBUG_VERIEXEC_FINGERPRINT 168 for (offset = 0; offset < ip->ops->digest_len; offset++) 169 printf("%02x", fingerprint[offset]); 170 printf("\n"); 171 #endif 172 173 failed: 174 free(ctx, M_VERIEXEC); 175 free(filebuf, M_VERIEXEC); 176 return (error); 177 } 178 179 /** 180 * @internal 181 * @brief Compare the two given fingerprints to see if they are the same. 182 * 183 * Differing fingerprint methods may have differing lengths which 184 * is handled by this routine. 185 * 186 * @param ip file info from the meta-data store 187 * @param digest digest to compare 188 * 189 * @return 0 if the fingerprints match and non-zero if they do not. 190 */ 191 static int 192 fingerprintcmp(struct mac_veriexec_file_info *ip, unsigned char *digest) 193 { 194 195 return memcmp(ip->fingerprint, digest, ip->ops->digest_len); 196 } 197 198 /** 199 * @brief Check if @p fingerprint matches the one associated with the vnode 200 * @p vp 201 * 202 * @param vp vnode to check 203 * @param ip file info from the meta-data store 204 * @param td calling thread 205 * @param file_size size of the file to read 206 * @param fingerprint fingerprint to compare 207 * 208 * @return 0 if they match, otherwise an error code. 209 */ 210 int 211 mac_veriexec_fingerprint_check_vnode(struct vnode *vp, 212 struct mac_veriexec_file_info *ip, struct thread *td, off_t file_size, 213 unsigned char *fingerprint) 214 { 215 int error; 216 217 /* reject fingerprint if writers are active */ 218 if (vp->v_writecount > 0) 219 return (ETXTBSY); 220 221 if ((vp->v_mount->mnt_flag & MNT_VERIFIED) != 0) { 222 VERIEXEC_DEBUG(2, ("file %ju.%lu on verified %s mount\n", 223 (uintmax_t)ip->fileid, ip->gen, 224 vp->v_mount->mnt_vfc->vfc_name)); 225 226 /* 227 * The VFS is backed by a file which has been verified. 228 * No need to waste time here. 229 */ 230 return (0); 231 } 232 233 error = evaluate_fingerprint(vp, ip, td, file_size, fingerprint); 234 if (error) 235 return (error); 236 237 if (fingerprintcmp(ip, fingerprint) != 0) 238 return (EAUTH); 239 240 return (0); 241 } 242 243 /** 244 * @brief Check a file signature and validate it. 245 * 246 * @param imgp parameters for the image to check 247 * @param check_files if 1, check the files list first, otherwise check the 248 * exectuables list first 249 * @param td calling thread 250 * 251 * @note Called with imgp->vp locked. 252 * 253 * @return 0 if the signature is valid, otherwise an error code. 254 */ 255 int 256 mac_veriexec_fingerprint_check_image(struct image_params *imgp, 257 int check_files, struct thread *td) 258 { 259 struct vnode *vp = imgp->vp; 260 int error; 261 fingerprint_status_t status; 262 263 if (!mac_veriexec_in_state(VERIEXEC_STATE_ACTIVE)) 264 return 0; 265 266 error = mac_veriexec_metadata_fetch_fingerprint_status(vp, imgp->attr, 267 td, check_files); 268 if (error && error != EAUTH) 269 return (error); 270 271 /* 272 * By now status is set. 273 */ 274 status = mac_veriexec_get_fingerprint_status(vp); 275 switch (status) { 276 case FINGERPRINT_INVALID: /* should not happen */ 277 identify_error(imgp, td, "got unexpected FINGERPRINT_INVALID"); 278 error = EPERM; 279 break; 280 281 case FINGERPRINT_FILE: 282 if (!check_files) { 283 if (prison0.pr_securelevel > 1 || 284 mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE)) 285 error = EPERM; 286 } 287 break; 288 289 case FINGERPRINT_VALID: /* is ok - report so if debug is on */ 290 VERIEXEC_DEBUG(4, ("Fingerprint matches\n")); 291 break; 292 293 case FINGERPRINT_INDIRECT: /* fingerprint ok but need to check 294 for direct execution */ 295 if (!imgp->interpreted) { 296 identify_error(imgp, td, "attempted direct execution"); 297 if (prison0.pr_securelevel > 1 || 298 mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE)) 299 error = EPERM; 300 } 301 break; 302 303 case FINGERPRINT_NOMATCH: /* does not match - whine about it */ 304 identify_error(imgp, td, 305 "fingerprint does not match loaded value"); 306 if (prison0.pr_securelevel > 1 || 307 mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE)) 308 error = EAUTH; 309 break; 310 311 case FINGERPRINT_NOENTRY: /* no entry in the list, complain */ 312 identify_error(imgp, td, "no fingerprint"); 313 if (prison0.pr_securelevel > 1 || 314 mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE)) 315 error = EAUTH; 316 break; 317 318 case FINGERPRINT_NODEV: /* no signatures for the device, complain */ 319 identify_error(imgp, td, "no signatures for device"); 320 if (prison0.pr_securelevel > 1 || 321 mac_veriexec_in_state(VERIEXEC_STATE_ENFORCE)) 322 error = EAUTH; 323 break; 324 325 default: /* this should never happen. */ 326 identify_error(imgp, td, "invalid status field for vnode"); 327 error = EPERM; 328 } 329 return error; 330 } 331 332 /** 333 * @brief Look up the fingerprint operations for a specific digest type 334 * 335 * @return A pointer to fingerprint operations, if found, or else @c NULL. 336 */ 337 struct mac_veriexec_fpops * 338 mac_veriexec_fingerprint_lookup_ops(const char *type) 339 { 340 struct mac_veriexec_fpops *fpops; 341 342 if (type == NULL) 343 return (NULL); 344 345 LIST_FOREACH(fpops, &fpops_list, entries) { 346 if (!strcasecmp(type, fpops->type)) 347 break; 348 } 349 return (fpops); 350 } 351 352 /** 353 * @brief Add fingerprint operations for a specific digest type 354 * 355 * Any attempts to add a duplicate digest type results in an error. 356 * 357 * @return 0 if the ops were added successfully, otherwise an error code. 358 */ 359 int 360 mac_veriexec_fingerprint_add_ops(struct mac_veriexec_fpops *fpops) 361 { 362 363 /* Sanity check the ops */ 364 if (fpops->type == NULL || fpops->digest_len == 0 || 365 fpops->context_size == 0 || fpops->init == NULL || 366 fpops->update == NULL || fpops->final == NULL) 367 return (EINVAL); 368 369 /* Make sure we do not already have ops for this digest type */ 370 if (mac_veriexec_fingerprint_lookup_ops(fpops->type)) 371 return (EEXIST); 372 373 /* Add the ops to the list */ 374 LIST_INSERT_HEAD(&fpops_list, fpops, entries); 375 376 printf("MAC/veriexec fingerprint module loaded: %s\n", fpops->type); 377 378 return (0); 379 } 380 381 /** 382 * @brief Initialize the fingerprint operations list 383 */ 384 void 385 mac_veriexec_fingerprint_init(void) 386 { 387 388 LIST_INIT(&fpops_list); 389 } 390 391 /** 392 * @brief Handle fingerprint module events 393 * 394 * This function is called by the @c MAC_VERIEXEC_FPMOD macro. 395 * 396 * @param mod module information 397 * @param type event type 398 * @param data event-specific data 399 * 400 * @return On @c MOD_LOAD, 0 if the fingerprint ops were added successfully, 401 * otherwise an error code. All other event types result in an error code. 402 */ 403 int 404 mac_veriexec_fingerprint_modevent(module_t mod, int type, void *data) 405 { 406 struct mac_veriexec_fpops *fpops; 407 int error; 408 409 error = 0; 410 fpops = (struct mac_veriexec_fpops *) data; 411 412 switch (type) { 413 case MOD_LOAD: 414 /* We do not allow late loading of fingerprint modules */ 415 if (mac_veriexec_late) { 416 printf("%s: can't load %s fingerprint module after " 417 "booting\n", __func__, fpops->type); 418 error = EBUSY; 419 break; 420 } 421 error = mac_veriexec_fingerprint_add_ops(fpops); 422 break; 423 case MOD_UNLOAD: 424 error = EBUSY; 425 break; 426 default: 427 error = EOPNOTSUPP; 428 break; 429 } 430 431 return (error); 432 } 433 434 /** 435 * @internal 436 * @brief Mark veriexec late initialization flag 437 */ 438 static void 439 mac_veriexec_late_init(void) 440 { 441 442 mac_veriexec_late = 1; 443 } 444 445 SYSINIT(mac_veriexec_late, SI_SUB_MAC_LATE, SI_ORDER_ANY, 446 mac_veriexec_late_init, NULL); 447