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