1 /* $NetBSD: kern_verifiedexec.c,v 1.9.2.31 2007/06/26 17:00:47 ghen Exp $ */
2
3 /*-
4 * Copyright 2005 Elad Efrat <elad@bsd.org.il>
5 * Copyright 2005 Brett Lymn <blymn@netbsd.org>
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Brett Lymn and Elad Efrat
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. Neither the name of The NetBSD Foundation nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.9.2.31 2007/06/26 17:00:47 ghen Exp $");
34
35 #include "opt_verified_exec.h"
36
37 #include <sys/param.h>
38 #include <sys/mount.h>
39 #include <sys/malloc.h>
40 #include <sys/vnode.h>
41 #include <sys/namei.h>
42 #include <sys/exec.h>
43 #include <sys/proc.h>
44 #include <sys/syslog.h>
45 #include <sys/sysctl.h>
46 #define VERIEXEC_NEED_NODE
47 #include <sys/verified_exec.h>
48 #if defined(__FreeBSD__)
49 # include <sys/systm.h>
50 # include <sys/imgact.h>
51 # include <crypto/sha1.h>
52 #else
53 # include <sys/sha1.h>
54 #endif
55 #include "crypto/sha2/sha2.h"
56 #include "crypto/ripemd160/rmd160.h"
57 #include <sys/md5.h>
58
59 int veriexec_verbose = 0;
60 int veriexec_strict = 0;
61
62 char *veriexec_fp_names = NULL;
63 unsigned int veriexec_name_max = 0;
64
65 struct sysctlnode *veriexec_count_node = NULL;
66
67 /* Veriexecs table of hash types and their associated information. */
68 LIST_HEAD(veriexec_ops_head, veriexec_fp_ops) veriexec_ops_list;
69
70 /*
71 * Add fingerprint names to the global list.
72 */
73 static void
74 veriexec_add_fp_name(char *name)
75 {
76 char *newp;
77 unsigned int new_max;
78
79 if (name == NULL)
80 return;
81
82 if (veriexec_fp_names == NULL) {
83 veriexec_name_max = (VERIEXEC_TYPE_MAXLEN + 1) * 6;
84 veriexec_fp_names = malloc(veriexec_name_max, M_TEMP, M_WAITOK);
85 memset(veriexec_fp_names, 0, veriexec_name_max);
86 }
87
88 if ((strlen(veriexec_fp_names) + VERIEXEC_TYPE_MAXLEN + 1) >=
89 veriexec_name_max) {
90 new_max = veriexec_name_max + 4 * (VERIEXEC_TYPE_MAXLEN + 1);
91 newp = realloc(veriexec_fp_names, new_max, M_TEMP, M_WAITOK);
92 veriexec_fp_names = newp;
93 veriexec_name_max = new_max;
94 }
95
96 strlcat(veriexec_fp_names, name, veriexec_name_max);
97 strlcat(veriexec_fp_names, " ", veriexec_name_max);
98 }
99
100 /*
101 * Add ops to the fignerprint ops vector list.
102 */
103 int veriexec_add_fp_ops(struct veriexec_fp_ops *ops)
104 {
105 if (ops == NULL)
106 return (EFAULT);
107
108 if ((ops->init == NULL) ||
109 (ops->update == NULL) ||
110 (ops->final == NULL))
111 return (EFAULT);
112
113 ops->type[sizeof(ops->type) - 1] = '\0';
114
115 #ifdef DIAGNOSTIC
116 if (veriexec_find_ops(ops->type) != NULL)
117 return (EEXIST);
118 #endif /* DIAGNOSTIC */
119
120 LIST_INSERT_HEAD(&veriexec_ops_list, ops, entries);
121 veriexec_add_fp_name(ops->type);
122
123 return (0);
124 }
125
126 /*
127 * Initialise the internal "default" fingerprint ops vector list.
128 */
129 void
130 veriexec_init_fp_ops(void)
131 {
132 struct veriexec_fp_ops *ops = NULL;
133
134 LIST_INIT(&veriexec_ops_list);
135
136 #ifdef VERIFIED_EXEC_FP_RMD160
137 ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
138 VERIEXEC_OPINIT(ops, "RMD160", RMD160_DIGEST_LENGTH,
139 sizeof(RMD160_CTX), RMD160Init, RMD160Update,
140 RMD160Final);
141 (void) veriexec_add_fp_ops(ops);
142 #endif /* VERIFIED_EXEC_FP_RMD160 */
143
144 #ifdef VERIFIED_EXEC_FP_SHA256
145 ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
146 VERIEXEC_OPINIT(ops, "SHA256", SHA256_DIGEST_LENGTH,
147 sizeof(SHA256_CTX), SHA256_Init, SHA256_Update,
148 SHA256_Final);
149 (void) veriexec_add_fp_ops(ops);
150 #endif /* VERIFIED_EXEC_FP_SHA256 */
151
152 #ifdef VERIFIED_EXEC_FP_SHA384
153 ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
154 VERIEXEC_OPINIT(ops, "SHA384", SHA384_DIGEST_LENGTH,
155 sizeof(SHA384_CTX), SHA384_Init, SHA384_Update,
156 SHA384_Final);
157 (void) veriexec_add_fp_ops(ops);
158 #endif /* VERIFIED_EXEC_FP_SHA384 */
159
160 #ifdef VERIFIED_EXEC_FP_SHA512
161 ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
162 VERIEXEC_OPINIT(ops, "SHA512", SHA512_DIGEST_LENGTH,
163 sizeof(SHA512_CTX), SHA512_Init, SHA512_Update,
164 SHA512_Final);
165 (void) veriexec_add_fp_ops(ops);
166 #endif /* VERIFIED_EXEC_FP_SHA512 */
167
168 #ifdef VERIFIED_EXEC_FP_SHA1
169 ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
170 VERIEXEC_OPINIT(ops, "SHA1", SHA1_DIGEST_LENGTH,
171 sizeof(SHA1_CTX), SHA1Init, SHA1Update,
172 SHA1Final);
173 (void) veriexec_add_fp_ops(ops);
174 #endif /* VERIFIED_EXEC_FP_SHA1 */
175
176 #ifdef VERIFIED_EXEC_FP_MD5
177 ops = (struct veriexec_fp_ops *) malloc(sizeof(*ops), M_TEMP, M_WAITOK);
178 VERIEXEC_OPINIT(ops, "MD5", MD5_DIGEST_LENGTH, sizeof(MD5_CTX),
179 MD5Init, MD5Update, MD5Final);
180 (void) veriexec_add_fp_ops(ops);
181 #endif /* VERIFIED_EXEC_FP_MD5 */
182 }
183
184 struct veriexec_fp_ops *
185 veriexec_find_ops(u_char *name)
186 {
187 struct veriexec_fp_ops *ops;
188
189 name[VERIEXEC_TYPE_MAXLEN] = '\0';
190
191 LIST_FOREACH(ops, &veriexec_ops_list, entries) {
192 if ((strlen(name) == strlen(ops->type)) &&
193 (strncasecmp(name, ops->type, sizeof(ops->type) - 1)
194 == 0))
195 return (ops);
196 }
197
198 return (NULL);
199 }
200
201 /*
202 * Calculate fingerprint. Information on hash length and routines used is
203 * extracted from veriexec_hash_list according to the hash type.
204 */
205 int
206 veriexec_fp_calc(struct proc *p, struct vnode *vp,
207 struct veriexec_hash_entry *vhe, uint64_t size, u_char *fp)
208 {
209 void *ctx = NULL;
210 u_char *buf = NULL;
211 off_t offset, len;
212 size_t resid;
213 int error = 0;
214
215 /* XXX: This should not happen. Print more details? */
216 if (vhe->ops == NULL) {
217 panic("veriexec: Operations vector is NULL");
218 }
219
220 memset(fp, 0, vhe->ops->hash_len);
221
222 ctx = (void *) malloc(vhe->ops->context_size, M_TEMP, M_WAITOK);
223 buf = (u_char *) malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
224
225 (vhe->ops->init)(ctx); /* init the fingerprint context */
226
227 /*
228 * The vnode is locked. sys_execve() does it for us; We have our
229 * own locking in vn_open().
230 */
231 for (offset = 0; offset < size; offset += PAGE_SIZE) {
232 len = ((size - offset) < PAGE_SIZE) ? (size - offset)
233 : PAGE_SIZE;
234
235 error = vn_rdwr(UIO_READ, vp, buf, len, offset,
236 UIO_SYSSPACE,
237 #ifdef __FreeBSD__
238 IO_NODELOCKED,
239 #else
240 0,
241 #endif
242 p->p_ucred, &resid, NULL);
243
244 if (error)
245 goto bad;
246
247 /* calculate fingerprint for each chunk */
248 (vhe->ops->update)(ctx, buf, (unsigned int) len);
249 }
250
251 /* finalise the fingerprint calculation */
252 (vhe->ops->final)(fp, ctx);
253
254 bad:
255 free(ctx, M_TEMP);
256 free(buf, M_TEMP);
257
258 return (error);
259 }
260
261 /* Compare two fingerprints of the same type. */
262 int
263 veriexec_fp_cmp(struct veriexec_fp_ops *ops, u_char *fp1, u_char *fp2)
264 {
265 if (veriexec_verbose >= 2) {
266 int i;
267
268 printf("comparing hashes...\n");
269 printf("fp1: ");
270 for (i = 0; i < ops->hash_len; i++) {
271 printf("%x", fp1[i]);
272 }
273 printf("\nfp2: ");
274 for (i = 0; i < ops->hash_len; i++) {
275 printf("%x", fp2[i]);
276 }
277 printf("\n");
278 }
279
280 return (memcmp(fp1, fp2, ops->hash_len));
281 }
282
283 /* Get the hash table for the specified device. */
284 struct veriexec_hashtbl *
285 veriexec_tblfind(dev_t device) {
286 struct veriexec_hashtbl *tbl;
287
288 LIST_FOREACH(tbl, &veriexec_tables, hash_list) {
289 if (tbl->hash_dev == device)
290 return (tbl);
291 }
292
293 return (NULL);
294 }
295
296 /* Perform a lookup on a hash table. */
297 struct veriexec_hash_entry *
298 veriexec_lookup(dev_t device, ino_t inode)
299 {
300 struct veriexec_hashtbl *tbl;
301 struct veriexec_hashhead *tble;
302 struct veriexec_hash_entry *e;
303 size_t indx;
304
305 tbl = veriexec_tblfind(device);
306 if (tbl == NULL)
307 return (NULL);
308
309 indx = VERIEXEC_HASH(tbl, inode);
310 tble = &(tbl->hash_tbl[indx & VERIEXEC_HASH_MASK(tbl)]);
311
312 LIST_FOREACH(e, tble, entries) {
313 if ((e != NULL) && (e->inode == inode))
314 return (e);
315 }
316
317 return (NULL);
318 }
319
320 /*
321 * Add an entry to a hash table. If a collision is found, handle it.
322 * The passed entry is allocated in kernel memory.
323 */
324 int
325 veriexec_hashadd(struct veriexec_hashtbl *tbl, struct veriexec_hash_entry *e)
326 {
327 struct veriexec_hashhead *vhh;
328 size_t indx;
329
330 if (tbl == NULL)
331 return (EFAULT);
332
333 indx = VERIEXEC_HASH(tbl, e->inode);
334 vhh = &(tbl->hash_tbl[indx]);
335
336 if (vhh == NULL)
337 panic("veriexec: veriexec_hashadd: vhh is NULL.");
338
339 LIST_INSERT_HEAD(vhh, e, entries);
340
341 tbl->hash_count++;
342
343 return (0);
344 }
345
346 /*
347 * Verify the fingerprint of the given file. If we're called directly from
348 * sys_execve(), 'flag' will be VERIEXEC_DIRECT. If we're called from
349 * exec_script(), 'flag' will be VERIEXEC_INDIRECT. If we are called from
350 * vn_open(), 'flag' will be VERIEXEC_FILE.
351 */
352 int
353 veriexec_verify(struct proc *p, struct vnode *vp, struct vattr *va,
354 const u_char *name, int flag, struct veriexec_hash_entry **ret)
355 {
356 struct veriexec_hash_entry *vhe = NULL;
357 u_char *digest = NULL;
358 int error = 0;
359
360 if (vp->v_type != VREG)
361 return (0);
362
363 /* Lookup veriexec table entry, save pointer if requested. */
364 /*
365 * XXX: Both va_fsid and va_fileid are long (32/64 bits), while
366 * XXX: veriexec_lookup() is passed dev_t and ino_t - uint32_t.
367 */
368 vhe = veriexec_lookup((dev_t)va->va_fsid, (ino_t)va->va_fileid);
369 if (ret != NULL)
370 *ret = vhe;
371 if (vhe == NULL)
372 goto out;
373
374 /* Evaluate fingerprint if needed. */
375 if (vhe->status == FINGERPRINT_NOTEVAL) {
376 /* Calculate fingerprint for on-disk file. */
377 digest = (u_char *) malloc(vhe->ops->hash_len, M_TEMP,
378 M_WAITOK);
379 error = veriexec_fp_calc(p, vp, vhe, va->va_size, digest);
380 if (error) {
381 veriexec_report("Fingerprint calculation error.",
382 name, va, NULL, REPORT_NOVERBOSE,
383 REPORT_NOALARM, REPORT_NOPANIC);
384 free(digest, M_TEMP);
385 return (error);
386 }
387
388 /* Compare fingerprint with loaded data. */
389 if (veriexec_fp_cmp(vhe->ops, vhe->fp, digest) == 0) {
390 vhe->status = FINGERPRINT_VALID;
391 } else {
392 vhe->status = FINGERPRINT_NOMATCH;
393 }
394
395 free(digest, M_TEMP);
396 }
397
398 if (!(vhe->type & flag)) {
399 veriexec_report("Incorrect access type.", name, va, p,
400 REPORT_NOVERBOSE, REPORT_ALARM,
401 REPORT_NOPANIC);
402
403 /* IPS mode: Enforce access type. */
404 if (veriexec_strict >= 2)
405 return (EPERM);
406 }
407
408 out:
409 /* No entry in the veriexec tables. */
410 if (vhe == NULL) {
411 veriexec_report("veriexec_verify: No entry.", name, va,
412 p, REPORT_VERBOSE, REPORT_NOALARM, REPORT_NOPANIC);
413
414 /* Lockdown mode: Deny access to non-monitored files if
415 * strict is 3 or higher, make an exception for executables
416 * since we don't want to run an unverified binary at strict
417 * 2 or higher.
418 */
419 if ((veriexec_strict >= 3) ||
420 ((veriexec_strict >= 2) && (flag != VERIEXEC_FILE)))
421 return (EPERM);
422
423 return (0);
424 }
425
426 switch (vhe->status) {
427 case FINGERPRINT_NOTEVAL:
428 /* Should not happen. */
429 veriexec_report("veriexec_verify: Not-evaluated status "
430 "post evaluation; inconsistency detected.", name, va,
431 NULL, REPORT_NOVERBOSE, REPORT_NOALARM, REPORT_PANIC);
432
433 case FINGERPRINT_VALID:
434 /* Valid fingerprint. */
435 veriexec_report("veriexec_verify: Match.", name, va, NULL,
436 REPORT_VERBOSE, REPORT_NOALARM, REPORT_NOPANIC);
437
438 break;
439
440 case FINGERPRINT_NOMATCH:
441 /* Fingerprint mismatch. */
442 veriexec_report("veriexec_verify: Mismatch.", name, va,
443 NULL, REPORT_NOVERBOSE, REPORT_ALARM, REPORT_NOPANIC);
444
445 /* IDS mode: Deny access on fingerprint mismatch. */
446 if (veriexec_strict >= 1)
447 error = EPERM;
448
449 break;
450
451 default:
452 /*
453 * Should never happen.
454 * XXX: Print vnode/process?
455 */
456 veriexec_report("veriexec_verify: Invalid stats "
457 "post evaluation.", name, va, NULL, REPORT_NOVERBOSE,
458 REPORT_NOALARM, REPORT_PANIC);
459 }
460
461 return (error);
462 }
463
464 /*
465 * Veriexec remove policy code.
466 */
467 int
468 veriexec_removechk(struct proc *p, struct vnode *vp, const char *pathbuf)
469 {
470 struct veriexec_hashtbl *tbl;
471 struct veriexec_hash_entry *vhe = NULL;
472 struct vattr va;
473 int error;
474
475 error = VOP_GETATTR(vp, &va, p->p_ucred, p);
476 if (error)
477 return (error);
478
479 vhe = veriexec_lookup(va.va_fsid, va.va_fileid);
480 if (vhe == NULL) {
481 /* Lockdown mode: Deny access to non-monitored files. */
482 if (veriexec_strict >= 3)
483 return (EPERM);
484
485 return (0);
486 }
487
488 veriexec_report("Remove request.", pathbuf, &va, p,
489 REPORT_NOVERBOSE, REPORT_ALARM, REPORT_NOPANIC);
490
491 /* IPS mode: Deny removal of monitored files. */
492 if (veriexec_strict >= 2)
493 return (EPERM);
494
495 tbl = veriexec_tblfind(va.va_fsid);
496 if (tbl == NULL) {
497 veriexec_report("veriexec_removechk: Inconsistency "
498 "detected: Could not get table for file in lists.",
499 pathbuf, &va, NULL, REPORT_NOVERBOSE, REPORT_NOALARM,
500 REPORT_PANIC);
501 }
502
503 LIST_REMOVE(vhe, entries);
504 if (vhe->fp != NULL)
505 free(vhe->fp, M_TEMP);
506 free(vhe, M_TEMP);
507 tbl->hash_count--;
508
509 return (error);
510 }
511
512 /*
513 * Veriexe rename policy.
514 */
515 int
516 veriexec_renamechk(struct vnode *vp, struct vnode *tvp, const char *from,
517 const char *to)
518 {
519 struct proc *p = curlwp->l_proc;
520 struct veriexec_hash_entry *vhe, *tvhe;
521 struct vattr va, tva;
522 int error;
523
524 error = VOP_GETATTR(vp, &va, p->p_ucred, p);
525 if (error)
526 return (error);
527
528 if (veriexec_strict >= 3) {
529 printf("Veriexec: veriexec_renamechk: Preventing rename "
530 "of \"%s\" [%ld:%llu] to \"%s\", uid=%u, pid=%u: "
531 "Lockdown mode.\n", from, va.va_fsid,
532 (unsigned long long)va.va_fileid,
533 to, p->p_ucred->cr_uid, p->p_pid);
534 return (EPERM);
535 }
536
537 /* XXX: dev_t and ino_t are 32bit, long can be 64bit. */
538 vhe = veriexec_lookup((dev_t)va.va_fsid, (ino_t)va.va_fileid);
539
540 if (tvp != NULL) {
541 error = VOP_GETATTR(tvp, &tva, p->p_ucred, p);
542 if (error)
543 return (error);
544 tvhe = veriexec_lookup((dev_t)tva.va_fsid,
545 (ino_t)tva.va_fileid);
546 } else
547 tvhe = NULL;
548
549 if ((vhe != NULL) || (tvhe != NULL)) {
550 if (veriexec_strict >= 2) {
551 printf("Veriexec: veriexec_renamechk: Preventing "
552 "rename of \"%s\" [%ld:%llu] to \"%s\", "
553 "uid=%u, pid=%u: IPS mode, file "
554 "monitored.\n", from, va.va_fsid,
555 (unsigned long long)va.va_fileid,
556 to, p->p_ucred->cr_uid, p->p_pid);
557 return (EPERM);
558 }
559
560 printf("Veriexec: veriexec_rename: Monitored file \"%s\" "
561 "[%ld:%llu] renamed to \"%s\", uid=%u, pid=%u.\n",
562 from, va.va_fsid, (unsigned long long)va.va_fileid, to,
563 p->p_ucred->cr_uid, p->p_pid);
564 }
565
566 return (0);
567 }
568
569 /*
570 * Routine for maintaining mostly consistent message formats in Verified
571 * Exec.
572 *
573 * 'verbose_only' - if 1, the message will be printed only if veriexec is
574 * in verbose mode.
575 * 'alarm' - if 1, the message is considered an alarm and will be printed
576 * at all times along with pid and user credentials.
577 * 'die' - if 1, the system will call panic() instead of printf().
578 */
579 void
580 veriexec_report(const u_char *msg, const u_char *filename,
581 struct vattr *va, struct proc *p, int verbose, int alarm,
582 int die)
583 {
584 void (*f)(const char *, ...);
585
586 if (msg == NULL || filename == NULL || va == NULL)
587 return;
588
589 if (die)
590 f = panic;
591 else
592 f = (void (*)(const char *, ...)) printf;
593
594 if (!verbose || (verbose == veriexec_verbose)) {
595 if (!alarm || p == NULL)
596 f("veriexec: %s [%s, %ld:%ld%s", msg, filename,
597 va->va_fsid, va->va_fileid,
598 die ? "]" : "]\n");
599 else
600 f("veriexec: %s [%s, %ld:%ld, pid=%u, uid=%u, "
601 "gid=%u%s", msg, filename, va->va_fsid,
602 va->va_fileid, p->p_pid, p->p_cred->p_ruid,
603 p->p_cred->p_rgid, die ? "]" : "]\n");
604 }
605 }
Cache object: 7fda958f1c4e3ee17b71e9720172aa69
|