| @@ -1,1166 +1,1166 @@ | | | @@ -1,1166 +1,1166 @@ |
1 | /* $NetBSD: kern_verifiedexec.c,v 1.123 2011/01/02 20:50:55 christos Exp $ */ | | 1 | /* $NetBSD: kern_verifiedexec.c,v 1.124 2011/01/08 20:29:13 christos Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org> | | 4 | * Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org> |
5 | * Copyright (c) 2005, 2006 Brett Lymn <blymn@NetBSD.org> | | 5 | * Copyright (c) 2005, 2006 Brett Lymn <blymn@NetBSD.org> |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | | 9 | * modification, are permitted provided that the following conditions |
10 | * are met: | | 10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright | | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | | 14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. | | 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 | | 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. | | 17 | * derived from this software without specific prior written permission. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR | | 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 | | 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
22 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, | | 22 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 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 | | 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 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 | | 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. | | 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | */ | | 29 | */ |
30 | | | 30 | |
31 | #include <sys/cdefs.h> | | 31 | #include <sys/cdefs.h> |
32 | __KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.123 2011/01/02 20:50:55 christos Exp $"); | | 32 | __KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.124 2011/01/08 20:29:13 christos Exp $"); |
33 | | | 33 | |
34 | #include "opt_veriexec.h" | | 34 | #include "opt_veriexec.h" |
35 | | | 35 | |
36 | #include <sys/param.h> | | 36 | #include <sys/param.h> |
37 | #include <sys/mount.h> | | 37 | #include <sys/mount.h> |
38 | #include <sys/kmem.h> | | 38 | #include <sys/kmem.h> |
39 | #include <sys/vnode.h> | | 39 | #include <sys/vnode.h> |
40 | #include <sys/namei.h> | | 40 | #include <sys/namei.h> |
41 | #include <sys/exec.h> | | 41 | #include <sys/exec.h> |
42 | #include <sys/once.h> | | 42 | #include <sys/once.h> |
43 | #include <sys/proc.h> | | 43 | #include <sys/proc.h> |
44 | #include <sys/rwlock.h> | | 44 | #include <sys/rwlock.h> |
45 | #include <sys/syslog.h> | | 45 | #include <sys/syslog.h> |
46 | #include <sys/sysctl.h> | | 46 | #include <sys/sysctl.h> |
47 | #include <sys/inttypes.h> | | 47 | #include <sys/inttypes.h> |
48 | #include <sys/verified_exec.h> | | 48 | #include <sys/verified_exec.h> |
49 | #if defined(__FreeBSD__) | | 49 | #if defined(__FreeBSD__) |
50 | # include <sys/systm.h> | | 50 | # include <sys/systm.h> |
51 | # include <sys/imgact.h> | | 51 | # include <sys/imgact.h> |
52 | # include <crypto/sha1.h> | | 52 | # include <crypto/sha1.h> |
53 | # include <crypto/sha2/sha2.h> | | 53 | # include <crypto/sha2/sha2.h> |
54 | # include <crypto/ripemd160/rmd160.h> | | 54 | # include <crypto/ripemd160/rmd160.h> |
55 | #else | | 55 | #else |
56 | # include <sys/sha1.h> | | 56 | # include <sys/sha1.h> |
57 | # include <sys/sha2.h> | | 57 | # include <sys/sha2.h> |
58 | # include <sys/rmd160.h> | | 58 | # include <sys/rmd160.h> |
59 | #endif | | 59 | #endif |
60 | #include <sys/md5.h> | | 60 | #include <sys/md5.h> |
61 | #include <uvm/uvm_extern.h> | | 61 | #include <uvm/uvm_extern.h> |
62 | #include <sys/fileassoc.h> | | 62 | #include <sys/fileassoc.h> |
63 | #include <sys/kauth.h> | | 63 | #include <sys/kauth.h> |
64 | #include <sys/conf.h> | | 64 | #include <sys/conf.h> |
65 | #include <miscfs/specfs/specdev.h> | | 65 | #include <miscfs/specfs/specdev.h> |
66 | #include <prop/proplib.h> | | 66 | #include <prop/proplib.h> |
67 | #include <sys/fcntl.h> | | 67 | #include <sys/fcntl.h> |
68 | | | 68 | |
69 | /* Readable values for veriexec_file_report(). */ | | 69 | /* Readable values for veriexec_file_report(). */ |
70 | #define REPORT_ALWAYS 0x01 /* Always print */ | | 70 | #define REPORT_ALWAYS 0x01 /* Always print */ |
71 | #define REPORT_VERBOSE 0x02 /* Print when verbose >= 1 */ | | 71 | #define REPORT_VERBOSE 0x02 /* Print when verbose >= 1 */ |
72 | #define REPORT_DEBUG 0x04 /* Print when verbose >= 2 (debug) */ | | 72 | #define REPORT_DEBUG 0x04 /* Print when verbose >= 2 (debug) */ |
73 | #define REPORT_PANIC 0x08 /* Call panic() */ | | 73 | #define REPORT_PANIC 0x08 /* Call panic() */ |
74 | #define REPORT_ALARM 0x10 /* Alarm - also print pid/uid/.. */ | | 74 | #define REPORT_ALARM 0x10 /* Alarm - also print pid/uid/.. */ |
75 | #define REPORT_LOGMASK (REPORT_ALWAYS|REPORT_VERBOSE|REPORT_DEBUG) | | 75 | #define REPORT_LOGMASK (REPORT_ALWAYS|REPORT_VERBOSE|REPORT_DEBUG) |
76 | | | 76 | |
77 | /* state of locking for veriexec_file_verify */ | | 77 | /* state of locking for veriexec_file_verify */ |
78 | #define VERIEXEC_UNLOCKED 0x00 /* Nothing locked, callee does it */ | | 78 | #define VERIEXEC_UNLOCKED 0x00 /* Nothing locked, callee does it */ |
79 | #define VERIEXEC_LOCKED 0x01 /* Global op lock held */ | | 79 | #define VERIEXEC_LOCKED 0x01 /* Global op lock held */ |
80 | | | 80 | |
81 | | | 81 | |
82 | #define VERIEXEC_RW_UPGRADE(lock) while((rw_tryupgrade(lock)) == 0){}; | | 82 | #define VERIEXEC_RW_UPGRADE(lock) while((rw_tryupgrade(lock)) == 0){}; |
83 | | | 83 | |
84 | struct veriexec_fpops { | | 84 | struct veriexec_fpops { |
85 | const char *type; | | 85 | const char *type; |
86 | size_t hash_len; | | 86 | size_t hash_len; |
87 | size_t context_size; | | 87 | size_t context_size; |
88 | veriexec_fpop_init_t init; | | 88 | veriexec_fpop_init_t init; |
89 | veriexec_fpop_update_t update; | | 89 | veriexec_fpop_update_t update; |
90 | veriexec_fpop_final_t final; | | 90 | veriexec_fpop_final_t final; |
91 | LIST_ENTRY(veriexec_fpops) entries; | | 91 | LIST_ENTRY(veriexec_fpops) entries; |
92 | }; | | 92 | }; |
93 | | | 93 | |
94 | /* Veriexec per-file entry data. */ | | 94 | /* Veriexec per-file entry data. */ |
95 | struct veriexec_file_entry { | | 95 | struct veriexec_file_entry { |
96 | krwlock_t lock; /* r/w lock */ | | 96 | krwlock_t lock; /* r/w lock */ |
97 | u_char *filename; /* File name. */ | | 97 | u_char *filename; /* File name. */ |
98 | u_char type; /* Entry type. */ | | 98 | u_char type; /* Entry type. */ |
99 | u_char status; /* Evaluation status. */ | | 99 | u_char status; /* Evaluation status. */ |
100 | u_char page_fp_status; /* Per-page FP status. */ | | 100 | u_char page_fp_status; /* Per-page FP status. */ |
101 | u_char *fp; /* Fingerprint. */ | | 101 | u_char *fp; /* Fingerprint. */ |
102 | void *page_fp; /* Per-page fingerprints */ | | 102 | void *page_fp; /* Per-page fingerprints */ |
103 | size_t npages; /* Number of pages. */ | | 103 | size_t npages; /* Number of pages. */ |
104 | size_t last_page_size; /* To support < PAGE_SIZE */ | | 104 | size_t last_page_size; /* To support < PAGE_SIZE */ |
105 | struct veriexec_fpops *ops; /* Fingerprint ops vector*/ | | 105 | struct veriexec_fpops *ops; /* Fingerprint ops vector*/ |
106 | size_t filename_len; /* Length of filename. */ | | 106 | size_t filename_len; /* Length of filename. */ |
107 | }; | | 107 | }; |
108 | | | 108 | |
109 | /* Veriexec per-table data. */ | | 109 | /* Veriexec per-table data. */ |
110 | struct veriexec_table_entry { | | 110 | struct veriexec_table_entry { |
111 | uint64_t vte_count; /* Number of Veriexec entries. */ | | 111 | uint64_t vte_count; /* Number of Veriexec entries. */ |
112 | const struct sysctlnode *vte_node; | | 112 | const struct sysctlnode *vte_node; |
113 | }; | | 113 | }; |
114 | | | 114 | |
115 | static int veriexec_verbose; | | 115 | static int veriexec_verbose; |
116 | int veriexec_strict; | | 116 | int veriexec_strict; |
117 | static int veriexec_bypass = 1; | | 117 | static int veriexec_bypass = 1; |
118 | | | 118 | |
119 | static char *veriexec_fp_names = NULL; | | 119 | static char *veriexec_fp_names = NULL; |
120 | static size_t veriexec_name_max = 0; | | 120 | static size_t veriexec_name_max = 0; |
121 | | | 121 | |
122 | static const struct sysctlnode *veriexec_count_node; | | 122 | static const struct sysctlnode *veriexec_count_node; |
123 | | | 123 | |
124 | static fileassoc_t veriexec_hook; | | 124 | static fileassoc_t veriexec_hook; |
125 | static specificdata_key_t veriexec_mountspecific_key; | | 125 | static specificdata_key_t veriexec_mountspecific_key; |
126 | | | 126 | |
127 | static LIST_HEAD(, veriexec_fpops) veriexec_fpops_list = | | 127 | static LIST_HEAD(, veriexec_fpops) veriexec_fpops_list = |
128 | LIST_HEAD_INITIALIZER(veriexec_fpops_list); | | 128 | LIST_HEAD_INITIALIZER(veriexec_fpops_list); |
129 | | | 129 | |
130 | static int veriexec_raw_cb(kauth_cred_t, kauth_action_t, void *, | | 130 | static int veriexec_raw_cb(kauth_cred_t, kauth_action_t, void *, |
131 | void *, void *, void *, void *); | | 131 | void *, void *, void *, void *); |
132 | static struct veriexec_fpops *veriexec_fpops_lookup(const char *); | | 132 | static struct veriexec_fpops *veriexec_fpops_lookup(const char *); |
133 | static void veriexec_file_free(struct veriexec_file_entry *); | | 133 | static void veriexec_file_free(struct veriexec_file_entry *); |
134 | | | 134 | |
135 | static unsigned int veriexec_tablecount = 0; | | 135 | static unsigned int veriexec_tablecount = 0; |
136 | | | 136 | |
137 | /* | | 137 | /* |
138 | * Veriexec operations global lock - most ops hold this as a read | | 138 | * Veriexec operations global lock - most ops hold this as a read |
139 | * lock, it is upgraded to a write lock when destroying veriexec file | | 139 | * lock, it is upgraded to a write lock when destroying veriexec file |
140 | * table entries. | | 140 | * table entries. |
141 | */ | | 141 | */ |
142 | static krwlock_t veriexec_op_lock; | | 142 | static krwlock_t veriexec_op_lock; |
143 | | | 143 | |
144 | /* | | 144 | /* |
145 | * Sysctl helper routine for Veriexec. | | 145 | * Sysctl helper routine for Veriexec. |
146 | */ | | 146 | */ |
147 | static int | | 147 | static int |
148 | sysctl_kern_veriexec_algorithms(SYSCTLFN_ARGS) | | 148 | sysctl_kern_veriexec_algorithms(SYSCTLFN_ARGS) |
149 | { | | 149 | { |
150 | size_t len; | | 150 | size_t len; |
151 | int error; | | 151 | int error; |
152 | const char *p; | | 152 | const char *p; |
153 | | | 153 | |
154 | if (newp != NULL) | | 154 | if (newp != NULL) |
155 | return EPERM; | | 155 | return EPERM; |
156 | | | 156 | |
157 | if (namelen != 0) | | 157 | if (namelen != 0) |
158 | return EINVAL; | | 158 | return EINVAL; |
159 | | | 159 | |
160 | p = veriexec_fp_names == NULL ? "" : veriexec_fp_names; | | 160 | p = veriexec_fp_names == NULL ? "" : veriexec_fp_names; |
161 | | | 161 | |
162 | len = strlen(p) + 1; | | 162 | len = strlen(p) + 1; |
163 | | | 163 | |
164 | if (*oldlenp < len) | | 164 | if (*oldlenp < len) |
165 | return ENOMEM; | | 165 | return ENOMEM; |
166 | | | 166 | |
167 | if ((error = copyout(p, oldp, len)) != 0) | | 167 | if (oldp && (error = copyout(p, oldp, len)) != 0) |
168 | return error; | | 168 | return error; |
169 | | | 169 | |
170 | *oldlenp = len; | | 170 | *oldlenp = len; |
171 | return 0; | | 171 | return 0; |
172 | } | | 172 | } |
173 | | | 173 | |
174 | static int | | 174 | static int |
175 | sysctl_kern_veriexec_strict(SYSCTLFN_ARGS) | | 175 | sysctl_kern_veriexec_strict(SYSCTLFN_ARGS) |
176 | { | | 176 | { |
177 | struct sysctlnode node; | | 177 | struct sysctlnode node; |
178 | int error, newval; | | 178 | int error, newval; |
179 | | | 179 | |
180 | node = *rnode; | | 180 | node = *rnode; |
181 | node.sysctl_data = &newval; | | 181 | node.sysctl_data = &newval; |
182 | | | 182 | |
183 | newval = veriexec_strict; | | 183 | newval = veriexec_strict; |
184 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); | | 184 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); |
185 | if (error || newp == NULL) | | 185 | if (error || newp == NULL) |
186 | return error; | | 186 | return error; |
187 | | | 187 | |
188 | if (newval < veriexec_strict) | | 188 | if (newval < veriexec_strict) |
189 | return EPERM; | | 189 | return EPERM; |
190 | | | 190 | |
191 | veriexec_strict = newval; | | 191 | veriexec_strict = newval; |
192 | | | 192 | |
193 | return 0; | | 193 | return 0; |
194 | } | | 194 | } |
195 | | | 195 | |
196 | SYSCTL_SETUP(sysctl_kern_veriexec_setup, "sysctl kern.veriexec setup") | | 196 | SYSCTL_SETUP(sysctl_kern_veriexec_setup, "sysctl kern.veriexec setup") |
197 | { | | 197 | { |
198 | const struct sysctlnode *rnode = NULL; | | 198 | const struct sysctlnode *rnode = NULL; |
199 | | | 199 | |
200 | sysctl_createv(clog, 0, NULL, &rnode, | | 200 | sysctl_createv(clog, 0, NULL, &rnode, |
201 | CTLFLAG_PERMANENT, | | 201 | CTLFLAG_PERMANENT, |
202 | CTLTYPE_NODE, "kern", NULL, | | 202 | CTLTYPE_NODE, "kern", NULL, |
203 | NULL, 0, NULL, 0, | | 203 | NULL, 0, NULL, 0, |
204 | CTL_KERN, CTL_EOL); | | 204 | CTL_KERN, CTL_EOL); |
205 | | | 205 | |
206 | sysctl_createv(clog, 0, &rnode, &rnode, | | 206 | sysctl_createv(clog, 0, &rnode, &rnode, |
207 | CTLFLAG_PERMANENT, | | 207 | CTLFLAG_PERMANENT, |
208 | CTLTYPE_NODE, "veriexec", | | 208 | CTLTYPE_NODE, "veriexec", |
209 | SYSCTL_DESCR("Veriexec"), | | 209 | SYSCTL_DESCR("Veriexec"), |
210 | NULL, 0, NULL, 0, | | 210 | NULL, 0, NULL, 0, |
211 | CTL_CREATE, CTL_EOL); | | 211 | CTL_CREATE, CTL_EOL); |
212 | | | 212 | |
213 | sysctl_createv(clog, 0, &rnode, NULL, | | 213 | sysctl_createv(clog, 0, &rnode, NULL, |
214 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, | | 214 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
215 | CTLTYPE_INT, "verbose", | | 215 | CTLTYPE_INT, "verbose", |
216 | SYSCTL_DESCR("Veriexec verbose level"), | | 216 | SYSCTL_DESCR("Veriexec verbose level"), |
217 | NULL, 0, &veriexec_verbose, 0, | | 217 | NULL, 0, &veriexec_verbose, 0, |
218 | CTL_CREATE, CTL_EOL); | | 218 | CTL_CREATE, CTL_EOL); |
219 | sysctl_createv(clog, 0, &rnode, NULL, | | 219 | sysctl_createv(clog, 0, &rnode, NULL, |
220 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, | | 220 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
221 | CTLTYPE_INT, "strict", | | 221 | CTLTYPE_INT, "strict", |
222 | SYSCTL_DESCR("Veriexec strict level"), | | 222 | SYSCTL_DESCR("Veriexec strict level"), |
223 | sysctl_kern_veriexec_strict, 0, NULL, 0, | | 223 | sysctl_kern_veriexec_strict, 0, NULL, 0, |
224 | CTL_CREATE, CTL_EOL); | | 224 | CTL_CREATE, CTL_EOL); |
225 | sysctl_createv(clog, 0, &rnode, NULL, | | 225 | sysctl_createv(clog, 0, &rnode, NULL, |
226 | CTLFLAG_PERMANENT, | | 226 | CTLFLAG_PERMANENT, |
227 | CTLTYPE_STRING, "algorithms", | | 227 | CTLTYPE_STRING, "algorithms", |
228 | SYSCTL_DESCR("Veriexec supported hashing " | | 228 | SYSCTL_DESCR("Veriexec supported hashing " |
229 | "algorithms"), | | 229 | "algorithms"), |
230 | sysctl_kern_veriexec_algorithms, 0, NULL, 0, | | 230 | sysctl_kern_veriexec_algorithms, 0, NULL, 0, |
231 | CTL_CREATE, CTL_EOL); | | 231 | CTL_CREATE, CTL_EOL); |
232 | sysctl_createv(clog, 0, &rnode, &veriexec_count_node, | | 232 | sysctl_createv(clog, 0, &rnode, &veriexec_count_node, |
233 | CTLFLAG_PERMANENT, | | 233 | CTLFLAG_PERMANENT, |
234 | CTLTYPE_NODE, "count", | | 234 | CTLTYPE_NODE, "count", |
235 | SYSCTL_DESCR("Number of fingerprints on mount(s)"), | | 235 | SYSCTL_DESCR("Number of fingerprints on mount(s)"), |
236 | NULL, 0, NULL, 0, | | 236 | NULL, 0, NULL, 0, |
237 | CTL_CREATE, CTL_EOL); | | 237 | CTL_CREATE, CTL_EOL); |
238 | } | | 238 | } |
239 | | | 239 | |
240 | /* | | 240 | /* |
241 | * Add ops to the fignerprint ops vector list. | | 241 | * Add ops to the fignerprint ops vector list. |
242 | */ | | 242 | */ |
243 | int | | 243 | int |
244 | veriexec_fpops_add(const char *fp_type, size_t hash_len, size_t ctx_size, | | 244 | veriexec_fpops_add(const char *fp_type, size_t hash_len, size_t ctx_size, |
245 | veriexec_fpop_init_t init, veriexec_fpop_update_t update, | | 245 | veriexec_fpop_init_t init, veriexec_fpop_update_t update, |
246 | veriexec_fpop_final_t final) | | 246 | veriexec_fpop_final_t final) |
247 | { | | 247 | { |
248 | struct veriexec_fpops *ops; | | 248 | struct veriexec_fpops *ops; |
249 | | | 249 | |
250 | /* Sanity check all parameters. */ | | 250 | /* Sanity check all parameters. */ |
251 | if ((fp_type == NULL) || (hash_len == 0) || (ctx_size == 0) || | | 251 | if ((fp_type == NULL) || (hash_len == 0) || (ctx_size == 0) || |
252 | (init == NULL) || (update == NULL) || (final == NULL)) | | 252 | (init == NULL) || (update == NULL) || (final == NULL)) |
253 | return (EFAULT); | | 253 | return (EFAULT); |
254 | | | 254 | |
255 | if (veriexec_fpops_lookup(fp_type) != NULL) | | 255 | if (veriexec_fpops_lookup(fp_type) != NULL) |
256 | return (EEXIST); | | 256 | return (EEXIST); |
257 | | | 257 | |
258 | ops = kmem_alloc(sizeof(*ops), KM_SLEEP); | | 258 | ops = kmem_alloc(sizeof(*ops), KM_SLEEP); |
259 | | | 259 | |
260 | ops->type = fp_type; | | 260 | ops->type = fp_type; |
261 | ops->hash_len = hash_len; | | 261 | ops->hash_len = hash_len; |
262 | ops->context_size = ctx_size; | | 262 | ops->context_size = ctx_size; |
263 | ops->init = init; | | 263 | ops->init = init; |
264 | ops->update = update; | | 264 | ops->update = update; |
265 | ops->final = final; | | 265 | ops->final = final; |
266 | | | 266 | |
267 | LIST_INSERT_HEAD(&veriexec_fpops_list, ops, entries); | | 267 | LIST_INSERT_HEAD(&veriexec_fpops_list, ops, entries); |
268 | | | 268 | |
269 | /* | | 269 | /* |
270 | * If we don't have space for any names, allocate enough for six | | 270 | * If we don't have space for any names, allocate enough for six |
271 | * which should be sufficient. (it's also enough for all algorithms | | 271 | * which should be sufficient. (it's also enough for all algorithms |
272 | * we can support at the moment) | | 272 | * we can support at the moment) |
273 | */ | | 273 | */ |
274 | if (veriexec_fp_names == NULL) { | | 274 | if (veriexec_fp_names == NULL) { |
275 | veriexec_name_max = 64; | | 275 | veriexec_name_max = 64; |
276 | veriexec_fp_names = kmem_zalloc(veriexec_name_max, KM_SLEEP); | | 276 | veriexec_fp_names = kmem_zalloc(veriexec_name_max, KM_SLEEP); |
277 | } | | 277 | } |
278 | | | 278 | |
279 | /* | | 279 | /* |
280 | * If we're running out of space for storing supported algorithms, | | 280 | * If we're running out of space for storing supported algorithms, |
281 | * extend the buffer with space for four names. | | 281 | * extend the buffer with space for four names. |
282 | */ | | 282 | */ |
283 | while (veriexec_name_max - (strlen(veriexec_fp_names) + 1) < | | 283 | while (veriexec_name_max - (strlen(veriexec_fp_names) + 1) < |
284 | strlen(fp_type)) { | | 284 | strlen(fp_type)) { |
285 | char *newp; | | 285 | char *newp; |
286 | unsigned int new_max; | | 286 | unsigned int new_max; |
287 | | | 287 | |
288 | /* Add space for four algorithm names. */ | | 288 | /* Add space for four algorithm names. */ |
289 | new_max = veriexec_name_max + 64; | | 289 | new_max = veriexec_name_max + 64; |
290 | newp = kmem_zalloc(new_max, KM_SLEEP); | | 290 | newp = kmem_zalloc(new_max, KM_SLEEP); |
291 | strlcpy(newp, veriexec_fp_names, new_max); | | 291 | strlcpy(newp, veriexec_fp_names, new_max); |
292 | kmem_free(veriexec_fp_names, veriexec_name_max); | | 292 | kmem_free(veriexec_fp_names, veriexec_name_max); |
293 | veriexec_fp_names = newp; | | 293 | veriexec_fp_names = newp; |
294 | veriexec_name_max = new_max; | | 294 | veriexec_name_max = new_max; |
295 | } | | 295 | } |
296 | | | 296 | |
297 | if (*veriexec_fp_names != '\0') | | 297 | if (*veriexec_fp_names != '\0') |
298 | strlcat(veriexec_fp_names, " ", veriexec_name_max); | | 298 | strlcat(veriexec_fp_names, " ", veriexec_name_max); |
299 | | | 299 | |
300 | strlcat(veriexec_fp_names, fp_type, veriexec_name_max); | | 300 | strlcat(veriexec_fp_names, fp_type, veriexec_name_max); |
301 | | | 301 | |
302 | return (0); | | 302 | return (0); |
303 | } | | 303 | } |
304 | | | 304 | |
305 | static void | | 305 | static void |
306 | veriexec_mountspecific_dtor(void *v) | | 306 | veriexec_mountspecific_dtor(void *v) |
307 | { | | 307 | { |
308 | struct veriexec_table_entry *vte = v; | | 308 | struct veriexec_table_entry *vte = v; |
309 | | | 309 | |
310 | if (vte == NULL) { | | 310 | if (vte == NULL) { |
311 | return; | | 311 | return; |
312 | } | | 312 | } |
313 | sysctl_free(__UNCONST(vte->vte_node)); | | 313 | sysctl_free(__UNCONST(vte->vte_node)); |
314 | veriexec_tablecount--; | | 314 | veriexec_tablecount--; |
315 | kmem_free(vte, sizeof(*vte)); | | 315 | kmem_free(vte, sizeof(*vte)); |
316 | } | | 316 | } |
317 | | | 317 | |
318 | /* | | 318 | /* |
319 | * Initialise Veriexec. | | 319 | * Initialise Veriexec. |
320 | */ | | 320 | */ |
321 | void | | 321 | void |
322 | veriexec_init(void) | | 322 | veriexec_init(void) |
323 | { | | 323 | { |
324 | int error; | | 324 | int error; |
325 | | | 325 | |
326 | /* Register a fileassoc for Veriexec. */ | | 326 | /* Register a fileassoc for Veriexec. */ |
327 | error = fileassoc_register("veriexec", | | 327 | error = fileassoc_register("veriexec", |
328 | (fileassoc_cleanup_cb_t)veriexec_file_free, &veriexec_hook); | | 328 | (fileassoc_cleanup_cb_t)veriexec_file_free, &veriexec_hook); |
329 | if (error) | | 329 | if (error) |
330 | panic("Veriexec: Can't register fileassoc: error=%d", error); | | 330 | panic("Veriexec: Can't register fileassoc: error=%d", error); |
331 | | | 331 | |
332 | /* Register listener to handle raw disk access. */ | | 332 | /* Register listener to handle raw disk access. */ |
333 | if (kauth_listen_scope(KAUTH_SCOPE_DEVICE, veriexec_raw_cb, NULL) == | | 333 | if (kauth_listen_scope(KAUTH_SCOPE_DEVICE, veriexec_raw_cb, NULL) == |
334 | NULL) | | 334 | NULL) |
335 | panic("Veriexec: Can't listen on device scope"); | | 335 | panic("Veriexec: Can't listen on device scope"); |
336 | | | 336 | |
337 | error = mount_specific_key_create(&veriexec_mountspecific_key, | | 337 | error = mount_specific_key_create(&veriexec_mountspecific_key, |
338 | veriexec_mountspecific_dtor); | | 338 | veriexec_mountspecific_dtor); |
339 | if (error) | | 339 | if (error) |
340 | panic("Veriexec: Can't create mountspecific key"); | | 340 | panic("Veriexec: Can't create mountspecific key"); |
341 | | | 341 | |
342 | rw_init(&veriexec_op_lock); | | 342 | rw_init(&veriexec_op_lock); |
343 | | | 343 | |
344 | #define FPOPS_ADD(a, b, c, d, e, f) \ | | 344 | #define FPOPS_ADD(a, b, c, d, e, f) \ |
345 | veriexec_fpops_add(a, b, c, (veriexec_fpop_init_t)d, \ | | 345 | veriexec_fpops_add(a, b, c, (veriexec_fpop_init_t)d, \ |
346 | (veriexec_fpop_update_t)e, (veriexec_fpop_final_t)f) | | 346 | (veriexec_fpop_update_t)e, (veriexec_fpop_final_t)f) |
347 | | | 347 | |
348 | #ifdef VERIFIED_EXEC_FP_RMD160 | | 348 | #ifdef VERIFIED_EXEC_FP_RMD160 |
349 | FPOPS_ADD("RMD160", RMD160_DIGEST_LENGTH, sizeof(RMD160_CTX), | | 349 | FPOPS_ADD("RMD160", RMD160_DIGEST_LENGTH, sizeof(RMD160_CTX), |
350 | RMD160Init, RMD160Update, RMD160Final); | | 350 | RMD160Init, RMD160Update, RMD160Final); |
351 | #endif /* VERIFIED_EXEC_FP_RMD160 */ | | 351 | #endif /* VERIFIED_EXEC_FP_RMD160 */ |
352 | | | 352 | |
353 | #ifdef VERIFIED_EXEC_FP_SHA256 | | 353 | #ifdef VERIFIED_EXEC_FP_SHA256 |
354 | FPOPS_ADD("SHA256", SHA256_DIGEST_LENGTH, sizeof(SHA256_CTX), | | 354 | FPOPS_ADD("SHA256", SHA256_DIGEST_LENGTH, sizeof(SHA256_CTX), |
355 | SHA256_Init, SHA256_Update, SHA256_Final); | | 355 | SHA256_Init, SHA256_Update, SHA256_Final); |
356 | #endif /* VERIFIED_EXEC_FP_SHA256 */ | | 356 | #endif /* VERIFIED_EXEC_FP_SHA256 */ |
357 | | | 357 | |
358 | #ifdef VERIFIED_EXEC_FP_SHA384 | | 358 | #ifdef VERIFIED_EXEC_FP_SHA384 |
359 | FPOPS_ADD("SHA384", SHA384_DIGEST_LENGTH, sizeof(SHA384_CTX), | | 359 | FPOPS_ADD("SHA384", SHA384_DIGEST_LENGTH, sizeof(SHA384_CTX), |
360 | SHA384_Init, SHA384_Update, SHA384_Final); | | 360 | SHA384_Init, SHA384_Update, SHA384_Final); |
361 | #endif /* VERIFIED_EXEC_FP_SHA384 */ | | 361 | #endif /* VERIFIED_EXEC_FP_SHA384 */ |
362 | | | 362 | |
363 | #ifdef VERIFIED_EXEC_FP_SHA512 | | 363 | #ifdef VERIFIED_EXEC_FP_SHA512 |
364 | FPOPS_ADD("SHA512", SHA512_DIGEST_LENGTH, sizeof(SHA512_CTX), | | 364 | FPOPS_ADD("SHA512", SHA512_DIGEST_LENGTH, sizeof(SHA512_CTX), |
365 | SHA512_Init, SHA512_Update, SHA512_Final); | | 365 | SHA512_Init, SHA512_Update, SHA512_Final); |
366 | #endif /* VERIFIED_EXEC_FP_SHA512 */ | | 366 | #endif /* VERIFIED_EXEC_FP_SHA512 */ |
367 | | | 367 | |
368 | #ifdef VERIFIED_EXEC_FP_SHA1 | | 368 | #ifdef VERIFIED_EXEC_FP_SHA1 |
369 | FPOPS_ADD("SHA1", SHA1_DIGEST_LENGTH, sizeof(SHA1_CTX), | | 369 | FPOPS_ADD("SHA1", SHA1_DIGEST_LENGTH, sizeof(SHA1_CTX), |
370 | SHA1Init, SHA1Update, SHA1Final); | | 370 | SHA1Init, SHA1Update, SHA1Final); |
371 | #endif /* VERIFIED_EXEC_FP_SHA1 */ | | 371 | #endif /* VERIFIED_EXEC_FP_SHA1 */ |
372 | | | 372 | |
373 | #ifdef VERIFIED_EXEC_FP_MD5 | | 373 | #ifdef VERIFIED_EXEC_FP_MD5 |
374 | FPOPS_ADD("MD5", MD5_DIGEST_LENGTH, sizeof(MD5_CTX), | | 374 | FPOPS_ADD("MD5", MD5_DIGEST_LENGTH, sizeof(MD5_CTX), |
375 | MD5Init, MD5Update, MD5Final); | | 375 | MD5Init, MD5Update, MD5Final); |
376 | #endif /* VERIFIED_EXEC_FP_MD5 */ | | 376 | #endif /* VERIFIED_EXEC_FP_MD5 */ |
377 | | | 377 | |
378 | #undef FPOPS_ADD | | 378 | #undef FPOPS_ADD |
379 | } | | 379 | } |
380 | | | 380 | |
381 | static struct veriexec_fpops * | | 381 | static struct veriexec_fpops * |
382 | veriexec_fpops_lookup(const char *name) | | 382 | veriexec_fpops_lookup(const char *name) |
383 | { | | 383 | { |
384 | struct veriexec_fpops *ops; | | 384 | struct veriexec_fpops *ops; |
385 | | | 385 | |
386 | if (name == NULL) | | 386 | if (name == NULL) |
387 | return (NULL); | | 387 | return (NULL); |
388 | | | 388 | |
389 | LIST_FOREACH(ops, &veriexec_fpops_list, entries) { | | 389 | LIST_FOREACH(ops, &veriexec_fpops_list, entries) { |
390 | if (strcasecmp(name, ops->type) == 0) | | 390 | if (strcasecmp(name, ops->type) == 0) |
391 | return (ops); | | 391 | return (ops); |
392 | } | | 392 | } |
393 | | | 393 | |
394 | return (NULL); | | 394 | return (NULL); |
395 | } | | 395 | } |
396 | | | 396 | |
397 | /* | | 397 | /* |
398 | * Calculate fingerprint. Information on hash length and routines used is | | 398 | * Calculate fingerprint. Information on hash length and routines used is |
399 | * extracted from veriexec_hash_list according to the hash type. | | 399 | * extracted from veriexec_hash_list according to the hash type. |
400 | * | | 400 | * |
401 | * NOTE: vfe is assumed to be locked for writing on entry. | | 401 | * NOTE: vfe is assumed to be locked for writing on entry. |
402 | */ | | 402 | */ |
403 | static int | | 403 | static int |
404 | veriexec_fp_calc(struct lwp *l, struct vnode *vp, int lock_state, | | 404 | veriexec_fp_calc(struct lwp *l, struct vnode *vp, int lock_state, |
405 | struct veriexec_file_entry *vfe, u_char *fp) | | 405 | struct veriexec_file_entry *vfe, u_char *fp) |
406 | { | | 406 | { |
407 | struct vattr va; | | 407 | struct vattr va; |
408 | void *ctx, *page_ctx; | | 408 | void *ctx, *page_ctx; |
409 | u_char *buf, *page_fp; | | 409 | u_char *buf, *page_fp; |
410 | off_t offset, len; | | 410 | off_t offset, len; |
411 | size_t resid, npages; | | 411 | size_t resid, npages; |
412 | int error, do_perpage, pagen; | | 412 | int error, do_perpage, pagen; |
413 | | | 413 | |
414 | error = VOP_GETATTR(vp, &va, l->l_cred); | | 414 | error = VOP_GETATTR(vp, &va, l->l_cred); |
415 | if (error) | | 415 | if (error) |
416 | return (error); | | 416 | return (error); |
417 | | | 417 | |
418 | #ifdef notyet /* XXX - for now */ | | 418 | #ifdef notyet /* XXX - for now */ |
419 | if ((vfe->type & VERIEXEC_UNTRUSTED) && | | 419 | if ((vfe->type & VERIEXEC_UNTRUSTED) && |
420 | (vfe->page_fp_status == PAGE_FP_NONE)) | | 420 | (vfe->page_fp_status == PAGE_FP_NONE)) |
421 | do_perpage = 1; | | 421 | do_perpage = 1; |
422 | else | | 422 | else |
423 | #endif /* notyet */ | | 423 | #endif /* notyet */ |
424 | do_perpage = 0; | | 424 | do_perpage = 0; |
425 | | | 425 | |
426 | ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP); | | 426 | ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP); |
427 | buf = kmem_alloc(PAGE_SIZE, KM_SLEEP); | | 427 | buf = kmem_alloc(PAGE_SIZE, KM_SLEEP); |
428 | | | 428 | |
429 | page_ctx = NULL; | | 429 | page_ctx = NULL; |
430 | page_fp = NULL; | | 430 | page_fp = NULL; |
431 | npages = 0; | | 431 | npages = 0; |
432 | if (do_perpage) { | | 432 | if (do_perpage) { |
433 | npages = (va.va_size >> PAGE_SHIFT) + 1; | | 433 | npages = (va.va_size >> PAGE_SHIFT) + 1; |
434 | page_fp = kmem_alloc(vfe->ops->hash_len * npages, KM_SLEEP); | | 434 | page_fp = kmem_alloc(vfe->ops->hash_len * npages, KM_SLEEP); |
435 | vfe->page_fp = page_fp; | | 435 | vfe->page_fp = page_fp; |
436 | page_ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP); | | 436 | page_ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP); |
437 | } | | 437 | } |
438 | | | 438 | |
439 | (vfe->ops->init)(ctx); | | 439 | (vfe->ops->init)(ctx); |
440 | | | 440 | |
441 | len = 0; | | 441 | len = 0; |
442 | error = 0; | | 442 | error = 0; |
443 | pagen = 0; | | 443 | pagen = 0; |
444 | for (offset = 0; offset < va.va_size; offset += PAGE_SIZE) { | | 444 | for (offset = 0; offset < va.va_size; offset += PAGE_SIZE) { |
445 | len = ((va.va_size - offset) < PAGE_SIZE) ? | | 445 | len = ((va.va_size - offset) < PAGE_SIZE) ? |
446 | (va.va_size - offset) : PAGE_SIZE; | | 446 | (va.va_size - offset) : PAGE_SIZE; |
447 | | | 447 | |
448 | error = vn_rdwr(UIO_READ, vp, buf, len, offset, | | 448 | error = vn_rdwr(UIO_READ, vp, buf, len, offset, |
449 | UIO_SYSSPACE, | | 449 | UIO_SYSSPACE, |
450 | ((lock_state == VERIEXEC_LOCKED)? | | 450 | ((lock_state == VERIEXEC_LOCKED)? |
451 | IO_NODELOCKED : 0), | | 451 | IO_NODELOCKED : 0), |
452 | l->l_cred, &resid, NULL); | | 452 | l->l_cred, &resid, NULL); |
453 | | | 453 | |
454 | if (error) { | | 454 | if (error) { |
455 | if (do_perpage) { | | 455 | if (do_perpage) { |
456 | kmem_free(vfe->page_fp, | | 456 | kmem_free(vfe->page_fp, |
457 | vfe->ops->hash_len * npages); | | 457 | vfe->ops->hash_len * npages); |
458 | vfe->page_fp = NULL; | | 458 | vfe->page_fp = NULL; |
459 | } | | 459 | } |
460 | | | 460 | |
461 | goto bad; | | 461 | goto bad; |
462 | } | | 462 | } |
463 | | | 463 | |
464 | (vfe->ops->update)(ctx, buf, (unsigned int) len); | | 464 | (vfe->ops->update)(ctx, buf, (unsigned int) len); |
465 | | | 465 | |
466 | if (do_perpage) { | | 466 | if (do_perpage) { |
467 | (vfe->ops->init)(page_ctx); | | 467 | (vfe->ops->init)(page_ctx); |
468 | (vfe->ops->update)(page_ctx, buf, (unsigned int)len); | | 468 | (vfe->ops->update)(page_ctx, buf, (unsigned int)len); |
469 | (vfe->ops->final)(page_fp, page_ctx); | | 469 | (vfe->ops->final)(page_fp, page_ctx); |
470 | | | 470 | |
471 | if (veriexec_verbose >= 2) { | | 471 | if (veriexec_verbose >= 2) { |
472 | int i; | | 472 | int i; |
473 | | | 473 | |
474 | printf("hash for page %d: ", pagen); | | 474 | printf("hash for page %d: ", pagen); |
475 | for (i = 0; i < vfe->ops->hash_len; i++) | | 475 | for (i = 0; i < vfe->ops->hash_len; i++) |
476 | printf("%02x", page_fp[i]); | | 476 | printf("%02x", page_fp[i]); |
477 | printf("\n"); | | 477 | printf("\n"); |
478 | } | | 478 | } |
479 | | | 479 | |
480 | page_fp += vfe->ops->hash_len; | | 480 | page_fp += vfe->ops->hash_len; |
481 | pagen++; | | 481 | pagen++; |
482 | } | | 482 | } |
483 | | | 483 | |
484 | if (len != PAGE_SIZE) | | 484 | if (len != PAGE_SIZE) |
485 | break; | | 485 | break; |
486 | } | | 486 | } |
487 | | | 487 | |
488 | (vfe->ops->final)(fp, ctx); | | 488 | (vfe->ops->final)(fp, ctx); |
489 | | | 489 | |
490 | if (do_perpage) { | | 490 | if (do_perpage) { |
491 | vfe->last_page_size = len; | | 491 | vfe->last_page_size = len; |
492 | vfe->page_fp_status = PAGE_FP_READY; | | 492 | vfe->page_fp_status = PAGE_FP_READY; |
493 | vfe->npages = npages; | | 493 | vfe->npages = npages; |
494 | } | | 494 | } |
495 | | | 495 | |
496 | bad: | | 496 | bad: |
497 | if (do_perpage) | | 497 | if (do_perpage) |
498 | kmem_free(page_ctx, vfe->ops->context_size); | | 498 | kmem_free(page_ctx, vfe->ops->context_size); |
499 | | | 499 | |
500 | kmem_free(ctx, vfe->ops->context_size); | | 500 | kmem_free(ctx, vfe->ops->context_size); |
501 | kmem_free(buf, PAGE_SIZE); | | 501 | kmem_free(buf, PAGE_SIZE); |
502 | | | 502 | |
503 | return (error); | | 503 | return (error); |
504 | } | | 504 | } |
505 | | | 505 | |
506 | /* Compare two fingerprints of the same type. */ | | 506 | /* Compare two fingerprints of the same type. */ |
507 | static int | | 507 | static int |
508 | veriexec_fp_cmp(struct veriexec_fpops *ops, u_char *fp1, u_char *fp2) | | 508 | veriexec_fp_cmp(struct veriexec_fpops *ops, u_char *fp1, u_char *fp2) |
509 | { | | 509 | { |
510 | if (veriexec_verbose >= 2) { | | 510 | if (veriexec_verbose >= 2) { |
511 | int i; | | 511 | int i; |
512 | | | 512 | |
513 | printf("comparing hashes...\n"); | | 513 | printf("comparing hashes...\n"); |
514 | printf("fp1: "); | | 514 | printf("fp1: "); |
515 | for (i = 0; i < ops->hash_len; i++) { | | 515 | for (i = 0; i < ops->hash_len; i++) { |
516 | printf("%02x", fp1[i]); | | 516 | printf("%02x", fp1[i]); |
517 | } | | 517 | } |
518 | printf("\nfp2: "); | | 518 | printf("\nfp2: "); |
519 | for (i = 0; i < ops->hash_len; i++) { | | 519 | for (i = 0; i < ops->hash_len; i++) { |
520 | printf("%02x", fp2[i]); | | 520 | printf("%02x", fp2[i]); |
521 | } | | 521 | } |
522 | printf("\n"); | | 522 | printf("\n"); |
523 | } | | 523 | } |
524 | | | 524 | |
525 | return (memcmp(fp1, fp2, ops->hash_len)); | | 525 | return (memcmp(fp1, fp2, ops->hash_len)); |
526 | } | | 526 | } |
527 | | | 527 | |
528 | static struct veriexec_table_entry * | | 528 | static struct veriexec_table_entry * |
529 | veriexec_table_lookup(struct mount *mp) | | 529 | veriexec_table_lookup(struct mount *mp) |
530 | { | | 530 | { |
531 | /* XXX: From raidframe init */ | | 531 | /* XXX: From raidframe init */ |
532 | if (mp == NULL) | | 532 | if (mp == NULL) |
533 | return NULL; | | 533 | return NULL; |
534 | | | 534 | |
535 | return mount_getspecific(mp, veriexec_mountspecific_key); | | 535 | return mount_getspecific(mp, veriexec_mountspecific_key); |
536 | } | | 536 | } |
537 | | | 537 | |
538 | static struct veriexec_file_entry * | | 538 | static struct veriexec_file_entry * |
539 | veriexec_get(struct vnode *vp) | | 539 | veriexec_get(struct vnode *vp) |
540 | { | | 540 | { |
541 | return (fileassoc_lookup(vp, veriexec_hook)); | | 541 | return (fileassoc_lookup(vp, veriexec_hook)); |
542 | } | | 542 | } |
543 | | | 543 | |
544 | bool | | 544 | bool |
545 | veriexec_lookup(struct vnode *vp) | | 545 | veriexec_lookup(struct vnode *vp) |
546 | { | | 546 | { |
547 | return (veriexec_get(vp) == NULL ? false : true); | | 547 | return (veriexec_get(vp) == NULL ? false : true); |
548 | } | | 548 | } |
549 | | | 549 | |
550 | /* | | 550 | /* |
551 | * Routine for maintaining mostly consistent message formats in Veriexec. | | 551 | * Routine for maintaining mostly consistent message formats in Veriexec. |
552 | */ | | 552 | */ |
553 | static void | | 553 | static void |
554 | veriexec_file_report(struct veriexec_file_entry *vfe, const u_char *msg, | | 554 | veriexec_file_report(struct veriexec_file_entry *vfe, const u_char *msg, |
555 | const u_char *filename, struct lwp *l, int f) | | 555 | const u_char *filename, struct lwp *l, int f) |
556 | { | | 556 | { |
557 | if (msg == NULL) | | 557 | if (msg == NULL) |
558 | return; | | 558 | return; |
559 | | | 559 | |
560 | if (vfe != NULL && vfe->filename != NULL) | | 560 | if (vfe != NULL && vfe->filename != NULL) |
561 | filename = vfe->filename; | | 561 | filename = vfe->filename; |
562 | | | 562 | |
563 | if (filename == NULL) | | 563 | if (filename == NULL) |
564 | return; | | 564 | return; |
565 | | | 565 | |
566 | if (((f & REPORT_LOGMASK) >> 1) <= veriexec_verbose) { | | 566 | if (((f & REPORT_LOGMASK) >> 1) <= veriexec_verbose) { |
567 | if (!(f & REPORT_ALARM) || (l == NULL)) | | 567 | if (!(f & REPORT_ALARM) || (l == NULL)) |
568 | log(LOG_NOTICE, "Veriexec: %s [%s]\n", msg, | | 568 | log(LOG_NOTICE, "Veriexec: %s [%s]\n", msg, |
569 | filename); | | 569 | filename); |
570 | else | | 570 | else |
571 | log(LOG_ALERT, "Veriexec: %s [%s, prog=%s pid=%u, " | | 571 | log(LOG_ALERT, "Veriexec: %s [%s, prog=%s pid=%u, " |
572 | "uid=%u, gid=%u]\n", msg, filename, | | 572 | "uid=%u, gid=%u]\n", msg, filename, |
573 | l->l_proc->p_comm, l->l_proc->p_pid, | | 573 | l->l_proc->p_comm, l->l_proc->p_pid, |
574 | kauth_cred_getuid(l->l_cred), | | 574 | kauth_cred_getuid(l->l_cred), |
575 | kauth_cred_getgid(l->l_cred)); | | 575 | kauth_cred_getgid(l->l_cred)); |
576 | } | | 576 | } |
577 | | | 577 | |
578 | if (f & REPORT_PANIC) | | 578 | if (f & REPORT_PANIC) |
579 | panic("Veriexec: Unrecoverable error."); | | 579 | panic("Veriexec: Unrecoverable error."); |
580 | } | | 580 | } |
581 | | | 581 | |
582 | /* | | 582 | /* |
583 | * Verify the fingerprint of the given file. If we're called directly from | | 583 | * Verify the fingerprint of the given file. If we're called directly from |
584 | * sys_execve(), 'flag' will be VERIEXEC_DIRECT. If we're called from | | 584 | * sys_execve(), 'flag' will be VERIEXEC_DIRECT. If we're called from |
585 | * exec_script(), 'flag' will be VERIEXEC_INDIRECT. If we are called from | | 585 | * exec_script(), 'flag' will be VERIEXEC_INDIRECT. If we are called from |
586 | * vn_open(), 'flag' will be VERIEXEC_FILE. | | 586 | * vn_open(), 'flag' will be VERIEXEC_FILE. |
587 | * | | 587 | * |
588 | * NOTE: The veriexec file entry pointer (vfep) will be returned LOCKED | | 588 | * NOTE: The veriexec file entry pointer (vfep) will be returned LOCKED |
589 | * on no error. | | 589 | * on no error. |
590 | */ | | 590 | */ |
591 | static int | | 591 | static int |
592 | veriexec_file_verify(struct lwp *l, struct vnode *vp, const u_char *name, | | 592 | veriexec_file_verify(struct lwp *l, struct vnode *vp, const u_char *name, |
593 | int flag, int lockstate, struct veriexec_file_entry **vfep) | | 593 | int flag, int lockstate, struct veriexec_file_entry **vfep) |
594 | { | | 594 | { |
595 | struct veriexec_file_entry *vfe; | | 595 | struct veriexec_file_entry *vfe; |
596 | int error; | | 596 | int error; |
597 | | | 597 | |
598 | #define VFE_NEEDS_EVAL(vfe) ((vfe->status == FINGERPRINT_NOTEVAL) || \ | | 598 | #define VFE_NEEDS_EVAL(vfe) ((vfe->status == FINGERPRINT_NOTEVAL) || \ |
599 | (vfe->type & VERIEXEC_UNTRUSTED)) | | 599 | (vfe->type & VERIEXEC_UNTRUSTED)) |
600 | | | 600 | |
601 | if (vfep != NULL) | | 601 | if (vfep != NULL) |
602 | *vfep = NULL; | | 602 | *vfep = NULL; |
603 | | | 603 | |
604 | if (vp->v_type != VREG) | | 604 | if (vp->v_type != VREG) |
605 | return (0); | | 605 | return (0); |
606 | | | 606 | |
607 | if (lockstate == VERIEXEC_UNLOCKED) | | 607 | if (lockstate == VERIEXEC_UNLOCKED) |
608 | rw_enter(&veriexec_op_lock, RW_READER); | | 608 | rw_enter(&veriexec_op_lock, RW_READER); |
609 | | | 609 | |
610 | /* Lookup veriexec table entry, save pointer if requested. */ | | 610 | /* Lookup veriexec table entry, save pointer if requested. */ |
611 | vfe = veriexec_get(vp); | | 611 | vfe = veriexec_get(vp); |
612 | if (vfep != NULL) | | 612 | if (vfep != NULL) |
613 | *vfep = vfe; | | 613 | *vfep = vfe; |
614 | if (vfe == NULL) | | 614 | if (vfe == NULL) |
615 | goto out; | | 615 | goto out; |
616 | | | 616 | |
617 | error = 0; | | 617 | error = 0; |
618 | | | 618 | |
619 | /* | | 619 | /* |
620 | * Grab the lock for the entry, if we need to do an evaluation | | 620 | * Grab the lock for the entry, if we need to do an evaluation |
621 | * then the lock is a write lock, after we have the write | | 621 | * then the lock is a write lock, after we have the write |
622 | * lock, check if we really need it - some other thread may | | 622 | * lock, check if we really need it - some other thread may |
623 | * have already done the work for us. | | 623 | * have already done the work for us. |
624 | */ | | 624 | */ |
625 | if (VFE_NEEDS_EVAL(vfe)) { | | 625 | if (VFE_NEEDS_EVAL(vfe)) { |
626 | rw_enter(&vfe->lock, RW_WRITER); | | 626 | rw_enter(&vfe->lock, RW_WRITER); |
627 | if (!VFE_NEEDS_EVAL(vfe)) | | 627 | if (!VFE_NEEDS_EVAL(vfe)) |
628 | rw_downgrade(&vfe->lock); | | 628 | rw_downgrade(&vfe->lock); |
629 | } else | | 629 | } else |
630 | rw_enter(&vfe->lock, RW_READER); | | 630 | rw_enter(&vfe->lock, RW_READER); |
631 | | | 631 | |
632 | /* Evaluate fingerprint if needed. */ | | 632 | /* Evaluate fingerprint if needed. */ |
633 | if (VFE_NEEDS_EVAL(vfe)) { | | 633 | if (VFE_NEEDS_EVAL(vfe)) { |
634 | u_char *digest; | | 634 | u_char *digest; |
635 | | | 635 | |
636 | /* Calculate fingerprint for on-disk file. */ | | 636 | /* Calculate fingerprint for on-disk file. */ |
637 | digest = kmem_zalloc(vfe->ops->hash_len, KM_SLEEP); | | 637 | digest = kmem_zalloc(vfe->ops->hash_len, KM_SLEEP); |
638 | | | 638 | |
639 | error = veriexec_fp_calc(l, vp, lockstate, vfe, digest); | | 639 | error = veriexec_fp_calc(l, vp, lockstate, vfe, digest); |
640 | if (error) { | | 640 | if (error) { |
641 | veriexec_file_report(vfe, "Fingerprint calculation error.", | | 641 | veriexec_file_report(vfe, "Fingerprint calculation error.", |
642 | name, NULL, REPORT_ALWAYS); | | 642 | name, NULL, REPORT_ALWAYS); |
643 | kmem_free(digest, vfe->ops->hash_len); | | 643 | kmem_free(digest, vfe->ops->hash_len); |
644 | rw_exit(&vfe->lock); | | 644 | rw_exit(&vfe->lock); |
645 | if (lockstate == VERIEXEC_UNLOCKED) | | 645 | if (lockstate == VERIEXEC_UNLOCKED) |
646 | rw_exit(&veriexec_op_lock); | | 646 | rw_exit(&veriexec_op_lock); |
647 | return (error); | | 647 | return (error); |
648 | } | | 648 | } |
649 | | | 649 | |
650 | /* Compare fingerprint with loaded data. */ | | 650 | /* Compare fingerprint with loaded data. */ |
651 | if (veriexec_fp_cmp(vfe->ops, vfe->fp, digest) == 0) | | 651 | if (veriexec_fp_cmp(vfe->ops, vfe->fp, digest) == 0) |
652 | vfe->status = FINGERPRINT_VALID; | | 652 | vfe->status = FINGERPRINT_VALID; |
653 | else | | 653 | else |
654 | vfe->status = FINGERPRINT_NOMATCH; | | 654 | vfe->status = FINGERPRINT_NOMATCH; |
655 | | | 655 | |
656 | kmem_free(digest, vfe->ops->hash_len); | | 656 | kmem_free(digest, vfe->ops->hash_len); |
657 | rw_downgrade(&vfe->lock); | | 657 | rw_downgrade(&vfe->lock); |
658 | } | | 658 | } |
659 | | | 659 | |
660 | if (!(vfe->type & flag)) { | | 660 | if (!(vfe->type & flag)) { |
661 | veriexec_file_report(vfe, "Incorrect access type.", name, l, | | 661 | veriexec_file_report(vfe, "Incorrect access type.", name, l, |
662 | REPORT_ALWAYS|REPORT_ALARM); | | 662 | REPORT_ALWAYS|REPORT_ALARM); |
663 | | | 663 | |
664 | /* IPS mode: Enforce access type. */ | | 664 | /* IPS mode: Enforce access type. */ |
665 | if (veriexec_strict >= VERIEXEC_IPS) { | | 665 | if (veriexec_strict >= VERIEXEC_IPS) { |
666 | rw_exit(&vfe->lock); | | 666 | rw_exit(&vfe->lock); |
667 | if (lockstate == VERIEXEC_UNLOCKED) | | 667 | if (lockstate == VERIEXEC_UNLOCKED) |
668 | rw_exit(&veriexec_op_lock); | | 668 | rw_exit(&veriexec_op_lock); |
669 | return (EPERM); | | 669 | return (EPERM); |
670 | } | | 670 | } |
671 | } | | 671 | } |
672 | | | 672 | |
673 | out: | | 673 | out: |
674 | /* No entry in the veriexec tables. */ | | 674 | /* No entry in the veriexec tables. */ |
675 | if (vfe == NULL) { | | 675 | if (vfe == NULL) { |
676 | veriexec_file_report(NULL, "No entry.", name, | | 676 | veriexec_file_report(NULL, "No entry.", name, |
677 | l, REPORT_VERBOSE); | | 677 | l, REPORT_VERBOSE); |
678 | | | 678 | |
679 | if (lockstate == VERIEXEC_UNLOCKED) | | 679 | if (lockstate == VERIEXEC_UNLOCKED) |
680 | rw_exit(&veriexec_op_lock); | | 680 | rw_exit(&veriexec_op_lock); |
681 | /* | | 681 | /* |
682 | * Lockdown mode: Deny access to non-monitored files. | | 682 | * Lockdown mode: Deny access to non-monitored files. |
683 | * IPS mode: Deny execution of non-monitored files. | | 683 | * IPS mode: Deny execution of non-monitored files. |
684 | */ | | 684 | */ |
685 | if ((veriexec_strict >= VERIEXEC_LOCKDOWN) || | | 685 | if ((veriexec_strict >= VERIEXEC_LOCKDOWN) || |
686 | ((veriexec_strict >= VERIEXEC_IPS) && | | 686 | ((veriexec_strict >= VERIEXEC_IPS) && |
687 | (flag != VERIEXEC_FILE))) | | 687 | (flag != VERIEXEC_FILE))) |
688 | return (EPERM); | | 688 | return (EPERM); |
689 | | | 689 | |
690 | return (0); | | 690 | return (0); |
691 | } | | 691 | } |
692 | | | 692 | |
693 | switch (vfe->status) { | | 693 | switch (vfe->status) { |
694 | case FINGERPRINT_NOTEVAL: | | 694 | case FINGERPRINT_NOTEVAL: |
695 | /* Should not happen. */ | | 695 | /* Should not happen. */ |
696 | rw_exit(&vfe->lock); | | 696 | rw_exit(&vfe->lock); |
697 | if (lockstate == VERIEXEC_UNLOCKED) | | 697 | if (lockstate == VERIEXEC_UNLOCKED) |
698 | rw_exit(&veriexec_op_lock); | | 698 | rw_exit(&veriexec_op_lock); |
699 | veriexec_file_report(vfe, "Not-evaluated status " | | 699 | veriexec_file_report(vfe, "Not-evaluated status " |
700 | "post evaluation; inconsistency detected.", name, | | 700 | "post evaluation; inconsistency detected.", name, |
701 | NULL, REPORT_ALWAYS|REPORT_PANIC); | | 701 | NULL, REPORT_ALWAYS|REPORT_PANIC); |
702 | | | 702 | |
703 | /*NOTREACHED*/ | | 703 | /*NOTREACHED*/ |
704 | | | 704 | |
705 | case FINGERPRINT_VALID: | | 705 | case FINGERPRINT_VALID: |
706 | /* Valid fingerprint. */ | | 706 | /* Valid fingerprint. */ |
707 | veriexec_file_report(vfe, "Match.", name, NULL, | | 707 | veriexec_file_report(vfe, "Match.", name, NULL, |
708 | REPORT_VERBOSE); | | 708 | REPORT_VERBOSE); |
709 | | | 709 | |
710 | break; | | 710 | break; |
711 | | | 711 | |
712 | case FINGERPRINT_NOMATCH: | | 712 | case FINGERPRINT_NOMATCH: |
713 | /* Fingerprint mismatch. */ | | 713 | /* Fingerprint mismatch. */ |
714 | veriexec_file_report(vfe, "Mismatch.", name, | | 714 | veriexec_file_report(vfe, "Mismatch.", name, |
715 | NULL, REPORT_ALWAYS|REPORT_ALARM); | | 715 | NULL, REPORT_ALWAYS|REPORT_ALARM); |
716 | | | 716 | |
717 | /* IDS mode: Deny access on fingerprint mismatch. */ | | 717 | /* IDS mode: Deny access on fingerprint mismatch. */ |
718 | if (veriexec_strict >= VERIEXEC_IDS) { | | 718 | if (veriexec_strict >= VERIEXEC_IDS) { |
719 | rw_exit(&vfe->lock); | | 719 | rw_exit(&vfe->lock); |
720 | error = EPERM; | | 720 | error = EPERM; |
721 | } | | 721 | } |
722 | | | 722 | |
723 | break; | | 723 | break; |
724 | | | 724 | |
725 | default: | | 725 | default: |
726 | /* Should never happen. */ | | 726 | /* Should never happen. */ |
727 | rw_exit(&vfe->lock); | | 727 | rw_exit(&vfe->lock); |
728 | if (lockstate == VERIEXEC_UNLOCKED) | | 728 | if (lockstate == VERIEXEC_UNLOCKED) |
729 | rw_exit(&veriexec_op_lock); | | 729 | rw_exit(&veriexec_op_lock); |
730 | veriexec_file_report(vfe, "Invalid status " | | 730 | veriexec_file_report(vfe, "Invalid status " |
731 | "post evaluation.", name, NULL, REPORT_ALWAYS|REPORT_PANIC); | | 731 | "post evaluation.", name, NULL, REPORT_ALWAYS|REPORT_PANIC); |
732 | } | | 732 | } |
733 | | | 733 | |
734 | if (lockstate == VERIEXEC_UNLOCKED) | | 734 | if (lockstate == VERIEXEC_UNLOCKED) |
735 | rw_exit(&veriexec_op_lock); | | 735 | rw_exit(&veriexec_op_lock); |
736 | return (error); | | 736 | return (error); |
737 | } | | 737 | } |
738 | | | 738 | |
739 | int | | 739 | int |
740 | veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag, | | 740 | veriexec_verify(struct lwp *l, struct vnode *vp, const u_char *name, int flag, |
741 | bool *found) | | 741 | bool *found) |
742 | { | | 742 | { |
743 | struct veriexec_file_entry *vfe; | | 743 | struct veriexec_file_entry *vfe; |
744 | int r; | | 744 | int r; |
745 | | | 745 | |
746 | if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) | | 746 | if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) |
747 | return 0; | | 747 | return 0; |
748 | | | 748 | |
749 | r = veriexec_file_verify(l, vp, name, flag, VERIEXEC_UNLOCKED, &vfe); | | 749 | r = veriexec_file_verify(l, vp, name, flag, VERIEXEC_UNLOCKED, &vfe); |
750 | | | 750 | |
751 | if ((r == 0) && (vfe != NULL)) | | 751 | if ((r == 0) && (vfe != NULL)) |
752 | rw_exit(&vfe->lock); | | 752 | rw_exit(&vfe->lock); |
753 | | | 753 | |
754 | if (found != NULL) | | 754 | if (found != NULL) |
755 | *found = (vfe != NULL) ? true : false; | | 755 | *found = (vfe != NULL) ? true : false; |
756 | | | 756 | |
757 | return (r); | | 757 | return (r); |
758 | } | | 758 | } |
759 | | | 759 | |
760 | #ifdef notyet | | 760 | #ifdef notyet |
761 | /* | | 761 | /* |
762 | * Evaluate per-page fingerprints. | | 762 | * Evaluate per-page fingerprints. |
763 | */ | | 763 | */ |
764 | int | | 764 | int |
765 | veriexec_page_verify(struct veriexec_file_entry *vfe, struct vm_page *pg, | | 765 | veriexec_page_verify(struct veriexec_file_entry *vfe, struct vm_page *pg, |
766 | size_t idx, struct lwp *l) | | 766 | size_t idx, struct lwp *l) |
767 | { | | 767 | { |
768 | void *ctx; | | 768 | void *ctx; |
769 | u_char *fp; | | 769 | u_char *fp; |
770 | u_char *page_fp; | | 770 | u_char *page_fp; |
771 | int error; | | 771 | int error; |
772 | vaddr_t kva; | | 772 | vaddr_t kva; |
773 | | | 773 | |
774 | if (vfe->page_fp_status == PAGE_FP_NONE) | | 774 | if (vfe->page_fp_status == PAGE_FP_NONE) |
775 | return (0); | | 775 | return (0); |
776 | | | 776 | |
777 | if (vfe->page_fp_status == PAGE_FP_FAIL) | | 777 | if (vfe->page_fp_status == PAGE_FP_FAIL) |
778 | return (EPERM); | | 778 | return (EPERM); |
779 | | | 779 | |
780 | if (idx >= vfe->npages) | | 780 | if (idx >= vfe->npages) |
781 | return (0); | | 781 | return (0); |
782 | | | 782 | |
783 | ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP); | | 783 | ctx = kmem_alloc(vfe->ops->context_size, KM_SLEEP); |
784 | fp = kmem_alloc(vfe->ops->hash_len, KM_SLEEP); | | 784 | fp = kmem_alloc(vfe->ops->hash_len, KM_SLEEP); |
785 | kva = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA); | | 785 | kva = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA); |
786 | pmap_kenter_pa(kva, VM_PAGE_TO_PHYS(pg), VM_PROT_READ, 0); | | 786 | pmap_kenter_pa(kva, VM_PAGE_TO_PHYS(pg), VM_PROT_READ, 0); |
787 | pmap_update(pmap_kernel()); | | 787 | pmap_update(pmap_kernel()); |
788 | | | 788 | |
789 | page_fp = (u_char *) vfe->page_fp + (vfe->ops->hash_len * idx); | | 789 | page_fp = (u_char *) vfe->page_fp + (vfe->ops->hash_len * idx); |
790 | (vfe->ops->init)(ctx); | | 790 | (vfe->ops->init)(ctx); |
791 | (vfe->ops->update)(ctx, (void *) kva, | | 791 | (vfe->ops->update)(ctx, (void *) kva, |
792 | ((vfe->npages - 1) == idx) ? vfe->last_page_size | | 792 | ((vfe->npages - 1) == idx) ? vfe->last_page_size |
793 | : PAGE_SIZE); | | 793 | : PAGE_SIZE); |
794 | (vfe->ops->final)(fp, ctx); | | 794 | (vfe->ops->final)(fp, ctx); |
795 | | | 795 | |
796 | pmap_kremove(kva, PAGE_SIZE); | | 796 | pmap_kremove(kva, PAGE_SIZE); |
797 | pmap_update(pmap_kernel()); | | 797 | pmap_update(pmap_kernel()); |
798 | uvm_km_free(kernel_map, kva, PAGE_SIZE, UVM_KMF_VAONLY); | | 798 | uvm_km_free(kernel_map, kva, PAGE_SIZE, UVM_KMF_VAONLY); |
799 | | | 799 | |
800 | error = veriexec_fp_cmp(vfe->ops, page_fp, fp); | | 800 | error = veriexec_fp_cmp(vfe->ops, page_fp, fp); |
801 | if (error) { | | 801 | if (error) { |
802 | const char *msg; | | 802 | const char *msg; |
803 | | | 803 | |
804 | if (veriexec_strict > VERIEXEC_LEARNING) { | | 804 | if (veriexec_strict > VERIEXEC_LEARNING) { |
805 | msg = "Pages modified: Killing process."; | | 805 | msg = "Pages modified: Killing process."; |
806 | } else { | | 806 | } else { |
807 | msg = "Pages modified."; | | 807 | msg = "Pages modified."; |
808 | error = 0; | | 808 | error = 0; |
809 | } | | 809 | } |
810 | | | 810 | |
811 | veriexec_file_report(msg, "[page_in]", l, | | 811 | veriexec_file_report(msg, "[page_in]", l, |
812 | REPORT_ALWAYS|REPORT_ALARM); | | 812 | REPORT_ALWAYS|REPORT_ALARM); |
813 | | | 813 | |
814 | if (error) { | | 814 | if (error) { |
815 | ksiginfo_t ksi; | | 815 | ksiginfo_t ksi; |
816 | | | 816 | |
817 | KSI_INIT(&ksi); | | 817 | KSI_INIT(&ksi); |
818 | ksi.ksi_signo = SIGKILL; | | 818 | ksi.ksi_signo = SIGKILL; |
819 | ksi.ksi_code = SI_NOINFO; | | 819 | ksi.ksi_code = SI_NOINFO; |
820 | ksi.ksi_pid = l->l_proc->p_pid; | | 820 | ksi.ksi_pid = l->l_proc->p_pid; |
821 | ksi.ksi_uid = 0; | | 821 | ksi.ksi_uid = 0; |
822 | | | 822 | |
823 | kpsignal(l->l_proc, &ksi, NULL); | | 823 | kpsignal(l->l_proc, &ksi, NULL); |
824 | } | | 824 | } |
825 | } | | 825 | } |
826 | | | 826 | |
827 | kmem_free(ctx, vfe->ops->context_size); | | 827 | kmem_free(ctx, vfe->ops->context_size); |
828 | kmem_free(fp, vfe->ops->hash_len); | | 828 | kmem_free(fp, vfe->ops->hash_len); |
829 | | | 829 | |
830 | return (error); | | 830 | return (error); |
831 | } | | 831 | } |
832 | #endif /* notyet */ | | 832 | #endif /* notyet */ |
833 | | | 833 | |
834 | /* | | 834 | /* |
835 | * Veriexec remove policy code. | | 835 | * Veriexec remove policy code. |
836 | */ | | 836 | */ |
837 | int | | 837 | int |
838 | veriexec_removechk(struct lwp *l, struct vnode *vp, const char *pathbuf) | | 838 | veriexec_removechk(struct lwp *l, struct vnode *vp, const char *pathbuf) |
839 | { | | 839 | { |
840 | struct veriexec_file_entry *vfe; | | 840 | struct veriexec_file_entry *vfe; |
841 | int error; | | 841 | int error; |
842 | | | 842 | |
843 | if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) | | 843 | if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) |
844 | return 0; | | 844 | return 0; |
845 | | | 845 | |
846 | rw_enter(&veriexec_op_lock, RW_READER); | | 846 | rw_enter(&veriexec_op_lock, RW_READER); |
847 | | | 847 | |
848 | vfe = veriexec_get(vp); | | 848 | vfe = veriexec_get(vp); |
849 | rw_exit(&veriexec_op_lock); | | 849 | rw_exit(&veriexec_op_lock); |
850 | | | 850 | |
851 | if (vfe == NULL) { | | 851 | if (vfe == NULL) { |
852 | /* Lockdown mode: Deny access to non-monitored files. */ | | 852 | /* Lockdown mode: Deny access to non-monitored files. */ |
853 | if (veriexec_strict >= VERIEXEC_LOCKDOWN) | | 853 | if (veriexec_strict >= VERIEXEC_LOCKDOWN) |
854 | return (EPERM); | | 854 | return (EPERM); |
855 | | | 855 | |
856 | return (0); | | 856 | return (0); |
857 | } | | 857 | } |
858 | | | 858 | |
859 | veriexec_file_report(vfe, "Remove request.", pathbuf, l, | | 859 | veriexec_file_report(vfe, "Remove request.", pathbuf, l, |
860 | REPORT_ALWAYS|REPORT_ALARM); | | 860 | REPORT_ALWAYS|REPORT_ALARM); |
861 | | | 861 | |
862 | /* IDS mode: Deny removal of monitored files. */ | | 862 | /* IDS mode: Deny removal of monitored files. */ |
863 | if (veriexec_strict >= VERIEXEC_IDS) | | 863 | if (veriexec_strict >= VERIEXEC_IDS) |
864 | error = EPERM; | | 864 | error = EPERM; |
865 | else | | 865 | else |
866 | error = veriexec_file_delete(l, vp); | | 866 | error = veriexec_file_delete(l, vp); |
867 | | | 867 | |
868 | | | 868 | |
869 | return error; | | 869 | return error; |
870 | } | | 870 | } |
871 | | | 871 | |
872 | /* | | 872 | /* |
873 | * Veriexec rename policy. | | 873 | * Veriexec rename policy. |
874 | * | | 874 | * |
875 | * XXX: Once there's a way to hook after a successful rename, it would be | | 875 | * XXX: Once there's a way to hook after a successful rename, it would be |
876 | * XXX: nice to update vfe->filename to the new name if it's not NULL and | | 876 | * XXX: nice to update vfe->filename to the new name if it's not NULL and |
877 | * XXX: the new name is absolute (ie., starts with a slash). | | 877 | * XXX: the new name is absolute (ie., starts with a slash). |
878 | */ | | 878 | */ |
879 | int | | 879 | int |
880 | veriexec_renamechk(struct lwp *l, struct vnode *fromvp, const char *fromname, | | 880 | veriexec_renamechk(struct lwp *l, struct vnode *fromvp, const char *fromname, |
881 | struct vnode *tovp, const char *toname) | | 881 | struct vnode *tovp, const char *toname) |
882 | { | | 882 | { |
883 | struct veriexec_file_entry *vfe, *tvfe; | | 883 | struct veriexec_file_entry *vfe, *tvfe; |
884 | | | 884 | |
885 | if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) | | 885 | if (veriexec_bypass && (veriexec_strict == VERIEXEC_LEARNING)) |
886 | return 0; | | 886 | return 0; |
887 | | | 887 | |
888 | rw_enter(&veriexec_op_lock, RW_READER); | | 888 | rw_enter(&veriexec_op_lock, RW_READER); |
889 | | | 889 | |
890 | if (veriexec_strict >= VERIEXEC_LOCKDOWN) { | | 890 | if (veriexec_strict >= VERIEXEC_LOCKDOWN) { |
891 | log(LOG_ALERT, "Veriexec: Preventing rename of `%s' to " | | 891 | log(LOG_ALERT, "Veriexec: Preventing rename of `%s' to " |
892 | "`%s', uid=%u, pid=%u: Lockdown mode.\n", fromname, toname, | | 892 | "`%s', uid=%u, pid=%u: Lockdown mode.\n", fromname, toname, |
893 | kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid); | | 893 | kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid); |
894 | | | 894 | |
895 | rw_exit(&veriexec_op_lock); | | 895 | rw_exit(&veriexec_op_lock); |
896 | return (EPERM); | | 896 | return (EPERM); |
897 | } | | 897 | } |
898 | | | 898 | |
899 | vfe = veriexec_get(fromvp); | | 899 | vfe = veriexec_get(fromvp); |
900 | tvfe = NULL; | | 900 | tvfe = NULL; |
901 | if (tovp != NULL) | | 901 | if (tovp != NULL) |
902 | tvfe = veriexec_get(tovp); | | 902 | tvfe = veriexec_get(tovp); |
903 | | | 903 | |
904 | if ((vfe != NULL) || (tvfe != NULL)) { | | 904 | if ((vfe != NULL) || (tvfe != NULL)) { |
905 | if (veriexec_strict >= VERIEXEC_IPS) { | | 905 | if (veriexec_strict >= VERIEXEC_IPS) { |
906 | log(LOG_ALERT, "Veriexec: Preventing rename of `%s' " | | 906 | log(LOG_ALERT, "Veriexec: Preventing rename of `%s' " |
907 | "to `%s', uid=%u, pid=%u: IPS mode, %s " | | 907 | "to `%s', uid=%u, pid=%u: IPS mode, %s " |
908 | "monitored.\n", fromname, toname, | | 908 | "monitored.\n", fromname, toname, |
909 | kauth_cred_geteuid(l->l_cred), | | 909 | kauth_cred_geteuid(l->l_cred), |
910 | l->l_proc->p_pid, (vfe != NULL && tvfe != NULL) ? | | 910 | l->l_proc->p_pid, (vfe != NULL && tvfe != NULL) ? |
911 | "files" : "file"); | | 911 | "files" : "file"); |
912 | | | 912 | |
913 | rw_exit(&veriexec_op_lock); | | 913 | rw_exit(&veriexec_op_lock); |
914 | return (EPERM); | | 914 | return (EPERM); |
915 | } | | 915 | } |
916 | | | 916 | |
917 | /* | | 917 | /* |
918 | * Monitored file is renamed; filename no longer relevant. | | 918 | * Monitored file is renamed; filename no longer relevant. |
919 | * | | 919 | * |
920 | * XXX: We could keep the buffer, and when (and if) updating the | | 920 | * XXX: We could keep the buffer, and when (and if) updating the |
921 | * XXX: filename post-rename, re-allocate it only if it's not | | 921 | * XXX: filename post-rename, re-allocate it only if it's not |
922 | * XXX: big enough for the new filename. | | 922 | * XXX: big enough for the new filename. |
923 | */ | | 923 | */ |
924 | if (vfe != NULL) { | | 924 | if (vfe != NULL) { |
925 | /* XXXX get write lock on vfe here? */ | | 925 | /* XXXX get write lock on vfe here? */ |
926 | | | 926 | |
927 | VERIEXEC_RW_UPGRADE(&veriexec_op_lock); | | 927 | VERIEXEC_RW_UPGRADE(&veriexec_op_lock); |
928 | /* once we have the op lock in write mode | | 928 | /* once we have the op lock in write mode |
929 | * there should be no locks on any file | | 929 | * there should be no locks on any file |
930 | * entries so we can destroy the object. | | 930 | * entries so we can destroy the object. |
931 | */ | | 931 | */ |
932 | | | 932 | |
933 | if (vfe->filename_len > 0) | | 933 | if (vfe->filename_len > 0) |
934 | kmem_free(vfe->filename, vfe->filename_len); | | 934 | kmem_free(vfe->filename, vfe->filename_len); |
935 | | | 935 | |
936 | vfe->filename = NULL; | | 936 | vfe->filename = NULL; |
937 | vfe->filename_len = 0; | | 937 | vfe->filename_len = 0; |
938 | | | 938 | |
939 | rw_downgrade(&veriexec_op_lock); | | 939 | rw_downgrade(&veriexec_op_lock); |
940 | } | | 940 | } |
941 | | | 941 | |
942 | log(LOG_NOTICE, "Veriexec: %s file `%s' renamed to " | | 942 | log(LOG_NOTICE, "Veriexec: %s file `%s' renamed to " |
943 | "%s file `%s', uid=%u, pid=%u.\n", (vfe != NULL) ? | | 943 | "%s file `%s', uid=%u, pid=%u.\n", (vfe != NULL) ? |
944 | "Monitored" : "Non-monitored", fromname, (tvfe != NULL) ? | | 944 | "Monitored" : "Non-monitored", fromname, (tvfe != NULL) ? |
945 | "monitored" : "non-monitored", toname, | | 945 | "monitored" : "non-monitored", toname, |
946 | kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid); | | 946 | kauth_cred_geteuid(l->l_cred), l->l_proc->p_pid); |
947 | | | 947 | |
948 | rw_exit(&veriexec_op_lock); | | 948 | rw_exit(&veriexec_op_lock); |
949 | | | 949 | |
950 | /* | | 950 | /* |
951 | * Monitored file is overwritten. Remove the entry. | | 951 | * Monitored file is overwritten. Remove the entry. |
952 | */ | | 952 | */ |
953 | if (tvfe != NULL) | | 953 | if (tvfe != NULL) |
954 | (void)veriexec_file_delete(l, tovp); | | 954 | (void)veriexec_file_delete(l, tovp); |
955 | | | 955 | |
956 | } else | | 956 | } else |
957 | rw_exit(&veriexec_op_lock); | | 957 | rw_exit(&veriexec_op_lock); |
958 | | | 958 | |
959 | return (0); | | 959 | return (0); |
960 | } | | 960 | } |
961 | | | 961 | |
962 | static void | | 962 | static void |
963 | veriexec_file_free(struct veriexec_file_entry *vfe) | | 963 | veriexec_file_free(struct veriexec_file_entry *vfe) |
964 | { | | 964 | { |
965 | if (vfe != NULL) { | | 965 | if (vfe != NULL) { |
966 | if (vfe->fp != NULL) | | 966 | if (vfe->fp != NULL) |
967 | kmem_free(vfe->fp, vfe->ops->hash_len); | | 967 | kmem_free(vfe->fp, vfe->ops->hash_len); |
968 | if (vfe->page_fp != NULL) | | 968 | if (vfe->page_fp != NULL) |
969 | kmem_free(vfe->page_fp, vfe->ops->hash_len); | | 969 | kmem_free(vfe->page_fp, vfe->ops->hash_len); |
970 | if (vfe->filename != NULL) | | 970 | if (vfe->filename != NULL) |
971 | kmem_free(vfe->filename, vfe->filename_len); | | 971 | kmem_free(vfe->filename, vfe->filename_len); |
972 | rw_destroy(&vfe->lock); | | 972 | rw_destroy(&vfe->lock); |
973 | kmem_free(vfe, sizeof(*vfe)); | | 973 | kmem_free(vfe, sizeof(*vfe)); |
974 | } | | 974 | } |
975 | } | | 975 | } |
976 | | | 976 | |
977 | static void | | 977 | static void |
978 | veriexec_file_purge(struct veriexec_file_entry *vfe, int have_lock) | | 978 | veriexec_file_purge(struct veriexec_file_entry *vfe, int have_lock) |
979 | { | | 979 | { |
980 | if (vfe == NULL) | | 980 | if (vfe == NULL) |
981 | return; | | 981 | return; |
982 | | | 982 | |
983 | if (have_lock == VERIEXEC_UNLOCKED) | | 983 | if (have_lock == VERIEXEC_UNLOCKED) |
984 | rw_enter(&vfe->lock, RW_WRITER); | | 984 | rw_enter(&vfe->lock, RW_WRITER); |
985 | else | | 985 | else |
986 | VERIEXEC_RW_UPGRADE(&vfe->lock); | | 986 | VERIEXEC_RW_UPGRADE(&vfe->lock); |
987 | | | 987 | |
988 | vfe->status = FINGERPRINT_NOTEVAL; | | 988 | vfe->status = FINGERPRINT_NOTEVAL; |
989 | if (have_lock == VERIEXEC_UNLOCKED) | | 989 | if (have_lock == VERIEXEC_UNLOCKED) |
990 | rw_exit(&vfe->lock); | | 990 | rw_exit(&vfe->lock); |
991 | else | | 991 | else |
992 | rw_downgrade(&vfe->lock); | | 992 | rw_downgrade(&vfe->lock); |
993 | } | | 993 | } |
994 | | | 994 | |
995 | static void | | 995 | static void |
996 | veriexec_file_purge_cb(struct veriexec_file_entry *vfe, void *cookie) | | 996 | veriexec_file_purge_cb(struct veriexec_file_entry *vfe, void *cookie) |
997 | { | | 997 | { |
998 | veriexec_file_purge(vfe, VERIEXEC_UNLOCKED); | | 998 | veriexec_file_purge(vfe, VERIEXEC_UNLOCKED); |
999 | } | | 999 | } |
1000 | | | 1000 | |
1001 | /* | | 1001 | /* |
1002 | * Invalidate a Veriexec file entry. | | 1002 | * Invalidate a Veriexec file entry. |
1003 | * XXX: This should be updated when per-page fingerprints are added. | | 1003 | * XXX: This should be updated when per-page fingerprints are added. |
1004 | */ | | 1004 | */ |
1005 | void | | 1005 | void |
1006 | veriexec_purge(struct vnode *vp) | | 1006 | veriexec_purge(struct vnode *vp) |
1007 | { | | 1007 | { |
1008 | | | 1008 | |
1009 | rw_enter(&veriexec_op_lock, RW_READER); | | 1009 | rw_enter(&veriexec_op_lock, RW_READER); |
1010 | veriexec_file_purge(veriexec_get(vp), VERIEXEC_UNLOCKED); | | 1010 | veriexec_file_purge(veriexec_get(vp), VERIEXEC_UNLOCKED); |
1011 | rw_exit(&veriexec_op_lock); | | 1011 | rw_exit(&veriexec_op_lock); |
1012 | } | | 1012 | } |
1013 | | | 1013 | |
1014 | /* | | 1014 | /* |
1015 | * Enforce raw disk access policy. | | 1015 | * Enforce raw disk access policy. |
1016 | * | | 1016 | * |
1017 | * IDS mode: Invalidate fingerprints on a mount if it's opened for writing. | | 1017 | * IDS mode: Invalidate fingerprints on a mount if it's opened for writing. |
1018 | * IPS mode: Don't allow raw writing to disks we monitor. | | 1018 | * IPS mode: Don't allow raw writing to disks we monitor. |
1019 | * Lockdown mode: Don't allow raw writing to all disks. | | 1019 | * Lockdown mode: Don't allow raw writing to all disks. |
1020 | * | | 1020 | * |
1021 | * XXX: This is bogus. There's an obvious race condition between the time | | 1021 | * XXX: This is bogus. There's an obvious race condition between the time |
1022 | * XXX: the disk is open for writing, in which an attacker can access a | | 1022 | * XXX: the disk is open for writing, in which an attacker can access a |
1023 | * XXX: monitored file to get its signature cached again, and when the raw | | 1023 | * XXX: monitored file to get its signature cached again, and when the raw |
1024 | * XXX: file is overwritten on disk. | | 1024 | * XXX: file is overwritten on disk. |
1025 | * XXX: | | 1025 | * XXX: |
1026 | * XXX: To solve this, we need something like the following: | | 1026 | * XXX: To solve this, we need something like the following: |
1027 | * XXX: open raw disk: | | 1027 | * XXX: open raw disk: |
1028 | * XXX: - raise refcount, | | 1028 | * XXX: - raise refcount, |
1029 | * XXX: - invalidate fingerprints, | | 1029 | * XXX: - invalidate fingerprints, |
1030 | * XXX: - mark all entries for that disk with "no cache" flag | | 1030 | * XXX: - mark all entries for that disk with "no cache" flag |
1031 | * XXX: | | 1031 | * XXX: |
1032 | * XXX: veriexec_verify: | | 1032 | * XXX: veriexec_verify: |
1033 | * XXX: - if "no cache", don't cache evaluation result | | 1033 | * XXX: - if "no cache", don't cache evaluation result |
1034 | * XXX: | | 1034 | * XXX: |
1035 | * XXX: close raw disk: | | 1035 | * XXX: close raw disk: |
1036 | * XXX: - lower refcount, | | 1036 | * XXX: - lower refcount, |
1037 | * XXX: - if refcount == 0, remove "no cache" flag from all entries | | 1037 | * XXX: - if refcount == 0, remove "no cache" flag from all entries |
1038 | */ | | 1038 | */ |
1039 | static int | | 1039 | static int |
1040 | veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, | | 1040 | veriexec_raw_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, |
1041 | void *arg0, void *arg1, void *arg2, void *arg3) | | 1041 | void *arg0, void *arg1, void *arg2, void *arg3) |
1042 | { | | 1042 | { |
1043 | int result; | | 1043 | int result; |
1044 | enum kauth_device_req req; | | 1044 | enum kauth_device_req req; |
1045 | struct veriexec_table_entry *vte; | | 1045 | struct veriexec_table_entry *vte; |
1046 | | | 1046 | |
1047 | result = KAUTH_RESULT_DENY; | | 1047 | result = KAUTH_RESULT_DENY; |
1048 | req = (enum kauth_device_req)arg0; | | 1048 | req = (enum kauth_device_req)arg0; |
1049 | | | 1049 | |
1050 | switch (action) { | | 1050 | switch (action) { |
1051 | case KAUTH_DEVICE_RAWIO_SPEC: { | | 1051 | case KAUTH_DEVICE_RAWIO_SPEC: { |
1052 | struct vnode *vp, *bvp; | | 1052 | struct vnode *vp, *bvp; |
1053 | int error; | | 1053 | int error; |
1054 | | | 1054 | |
1055 | if (req == KAUTH_REQ_DEVICE_RAWIO_SPEC_READ) { | | 1055 | if (req == KAUTH_REQ_DEVICE_RAWIO_SPEC_READ) { |
1056 | result = KAUTH_RESULT_DEFER; | | 1056 | result = KAUTH_RESULT_DEFER; |
1057 | break; | | 1057 | break; |
1058 | } | | 1058 | } |
1059 | | | 1059 | |
1060 | vp = arg1; | | 1060 | vp = arg1; |
1061 | KASSERT(vp != NULL); | | 1061 | KASSERT(vp != NULL); |
1062 | | | 1062 | |
1063 | /* Handle /dev/mem and /dev/kmem. */ | | 1063 | /* Handle /dev/mem and /dev/kmem. */ |
1064 | if (iskmemvp(vp)) { | | 1064 | if (iskmemvp(vp)) { |
1065 | if (veriexec_strict < VERIEXEC_IPS) | | 1065 | if (veriexec_strict < VERIEXEC_IPS) |
1066 | result = KAUTH_RESULT_DEFER; | | 1066 | result = KAUTH_RESULT_DEFER; |
1067 | | | 1067 | |
1068 | break; | | 1068 | break; |
1069 | } | | 1069 | } |
1070 | | | 1070 | |
1071 | error = rawdev_mounted(vp, &bvp); | | 1071 | error = rawdev_mounted(vp, &bvp); |
1072 | if (error == EINVAL) { | | 1072 | if (error == EINVAL) { |
1073 | result = KAUTH_RESULT_DEFER; | | 1073 | result = KAUTH_RESULT_DEFER; |
1074 | break; | | 1074 | break; |
1075 | } | | 1075 | } |
1076 | | | 1076 | |
1077 | /* | | 1077 | /* |
1078 | * XXX: See vfs_mountedon() comment in rawdev_mounted(). | | 1078 | * XXX: See vfs_mountedon() comment in rawdev_mounted(). |
1079 | */ | | 1079 | */ |
1080 | vte = veriexec_table_lookup(bvp->v_mount); | | 1080 | vte = veriexec_table_lookup(bvp->v_mount); |
1081 | if (vte == NULL) { | | 1081 | if (vte == NULL) { |
1082 | result = KAUTH_RESULT_DEFER; | | 1082 | result = KAUTH_RESULT_DEFER; |
1083 | break; | | 1083 | break; |
1084 | } | | 1084 | } |
1085 | | | 1085 | |
1086 | switch (veriexec_strict) { | | 1086 | switch (veriexec_strict) { |
1087 | case VERIEXEC_LEARNING: | | 1087 | case VERIEXEC_LEARNING: |
1088 | case VERIEXEC_IDS: | | 1088 | case VERIEXEC_IDS: |
1089 | result = KAUTH_RESULT_DEFER; | | 1089 | result = KAUTH_RESULT_DEFER; |
1090 | | | 1090 | |
1091 | rw_enter(&veriexec_op_lock, RW_WRITER); | | 1091 | rw_enter(&veriexec_op_lock, RW_WRITER); |
1092 | fileassoc_table_run(bvp->v_mount, veriexec_hook, | | 1092 | fileassoc_table_run(bvp->v_mount, veriexec_hook, |
1093 | (fileassoc_cb_t)veriexec_file_purge_cb, NULL); | | 1093 | (fileassoc_cb_t)veriexec_file_purge_cb, NULL); |
1094 | rw_exit(&veriexec_op_lock); | | 1094 | rw_exit(&veriexec_op_lock); |
1095 | | | 1095 | |
1096 | break; | | 1096 | break; |
1097 | case VERIEXEC_IPS: | | 1097 | case VERIEXEC_IPS: |
1098 | result = KAUTH_RESULT_DENY; | | 1098 | result = KAUTH_RESULT_DENY; |
1099 | break; | | 1099 | break; |
1100 | case VERIEXEC_LOCKDOWN: | | 1100 | case VERIEXEC_LOCKDOWN: |
1101 | result = KAUTH_RESULT_DENY; | | 1101 | result = KAUTH_RESULT_DENY; |
1102 | break; | | 1102 | break; |
1103 | } | | 1103 | } |
1104 | | | 1104 | |
1105 | break; | | 1105 | break; |
1106 | } | | 1106 | } |
1107 | | | 1107 | |
1108 | case KAUTH_DEVICE_RAWIO_PASSTHRU: | | 1108 | case KAUTH_DEVICE_RAWIO_PASSTHRU: |
1109 | /* XXX What can we do here? */ | | 1109 | /* XXX What can we do here? */ |
1110 | if (veriexec_strict < VERIEXEC_IPS) | | 1110 | if (veriexec_strict < VERIEXEC_IPS) |
1111 | result = KAUTH_RESULT_DEFER; | | 1111 | result = KAUTH_RESULT_DEFER; |
1112 | | | 1112 | |
1113 | break; | | 1113 | break; |
1114 | | | 1114 | |
1115 | default: | | 1115 | default: |
1116 | result = KAUTH_RESULT_DEFER; | | 1116 | result = KAUTH_RESULT_DEFER; |
1117 | break; | | 1117 | break; |
1118 | } | | 1118 | } |
1119 | | | 1119 | |
1120 | return (result); | | 1120 | return (result); |
1121 | } | | 1121 | } |
1122 | | | 1122 | |
1123 | /* | | 1123 | /* |
1124 | * Create a new Veriexec table. | | 1124 | * Create a new Veriexec table. |
1125 | */ | | 1125 | */ |
1126 | static struct veriexec_table_entry * | | 1126 | static struct veriexec_table_entry * |
1127 | veriexec_table_add(struct lwp *l, struct mount *mp) | | 1127 | veriexec_table_add(struct lwp *l, struct mount *mp) |
1128 | { | | 1128 | { |
1129 | struct veriexec_table_entry *vte; | | 1129 | struct veriexec_table_entry *vte; |
1130 | u_char buf[16]; | | 1130 | u_char buf[16]; |
1131 | | | 1131 | |
1132 | vte = kmem_zalloc(sizeof(*vte), KM_SLEEP); | | 1132 | vte = kmem_zalloc(sizeof(*vte), KM_SLEEP); |
1133 | mount_setspecific(mp, veriexec_mountspecific_key, vte); | | 1133 | mount_setspecific(mp, veriexec_mountspecific_key, vte); |
1134 | | | 1134 | |
1135 | snprintf(buf, sizeof(buf), "table%u", veriexec_tablecount++); | | 1135 | snprintf(buf, sizeof(buf), "table%u", veriexec_tablecount++); |
1136 | sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node, | | 1136 | sysctl_createv(NULL, 0, &veriexec_count_node, &vte->vte_node, |
1137 | 0, CTLTYPE_NODE, buf, NULL, NULL, 0, NULL, | | 1137 | 0, CTLTYPE_NODE, buf, NULL, NULL, 0, NULL, |
1138 | 0, CTL_CREATE, CTL_EOL); | | 1138 | 0, CTL_CREATE, CTL_EOL); |
1139 | | | 1139 | |
1140 | sysctl_createv(NULL, 0, &vte->vte_node, NULL, | | 1140 | sysctl_createv(NULL, 0, &vte->vte_node, NULL, |
1141 | CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt", | | 1141 | CTLFLAG_READONLY, CTLTYPE_STRING, "mntpt", |
1142 | NULL, NULL, 0, mp->mnt_stat.f_mntonname, | | 1142 | NULL, NULL, 0, mp->mnt_stat.f_mntonname, |
1143 | 0, CTL_CREATE, CTL_EOL); | | 1143 | 0, CTL_CREATE, CTL_EOL); |
1144 | sysctl_createv(NULL, 0, &vte->vte_node, NULL, | | 1144 | sysctl_createv(NULL, 0, &vte->vte_node, NULL, |
1145 | CTLFLAG_READONLY, CTLTYPE_STRING, "fstype", | | 1145 | CTLFLAG_READONLY, CTLTYPE_STRING, "fstype", |
1146 | NULL, NULL, 0, mp->mnt_stat.f_fstypename, | | 1146 | NULL, NULL, 0, mp->mnt_stat.f_fstypename, |
1147 | 0, CTL_CREATE, CTL_EOL); | | 1147 | 0, CTL_CREATE, CTL_EOL); |
1148 | sysctl_createv(NULL, 0, &vte->vte_node, NULL, | | 1148 | sysctl_createv(NULL, 0, &vte->vte_node, NULL, |
1149 | CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries", | | 1149 | CTLFLAG_READONLY, CTLTYPE_QUAD, "nentries", |
1150 | NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL); | | 1150 | NULL, NULL, 0, &vte->vte_count, 0, CTL_CREATE, CTL_EOL); |
1151 | | | 1151 | |
1152 | return (vte); | | 1152 | return (vte); |
1153 | } | | 1153 | } |
1154 | | | 1154 | |
1155 | /* | | 1155 | /* |
1156 | * Add a file to be monitored by Veriexec. | | 1156 | * Add a file to be monitored by Veriexec. |
1157 | * | | 1157 | * |
1158 | * Expected elements in dict: file, fp, fp-type, entry-type. | | 1158 | * Expected elements in dict: file, fp, fp-type, entry-type. |
1159 | */ | | 1159 | */ |
1160 | int | | 1160 | int |
1161 | veriexec_file_add(struct lwp *l, prop_dictionary_t dict) | | 1161 | veriexec_file_add(struct lwp *l, prop_dictionary_t dict) |
1162 | { | | 1162 | { |
1163 | struct veriexec_table_entry *vte; | | 1163 | struct veriexec_table_entry *vte; |
1164 | struct veriexec_file_entry *vfe = NULL, *hh; | | 1164 | struct veriexec_file_entry *vfe = NULL, *hh; |
1165 | struct vnode *vp; | | 1165 | struct vnode *vp; |
1166 | const char *file, *fp_type; | | 1166 | const char *file, *fp_type; |