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