1 /* $NetBSD: kern_verifiedexec.c,v 1.7 2003/11/18 13:13:03 martin Exp $ */
2
3 /*-
4 * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Brett Lymn and Jason R Fink
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: kern_verifiedexec.c,v 1.7 2003/11/18 13:13:03 martin Exp $");
41
42 #include <sys/param.h>
43 #include <sys/mount.h>
44 #include <sys/malloc.h>
45 #include <sys/vnode.h>
46 #include <sys/exec.h>
47 #include <sys/md5.h>
48 #include <sys/sha1.h>
49 #include <sys/verified_exec.h>
50
51 /* Set the buffer to a single page for md5 and sha1 */
52 #define BUF_SIZE PAGE_SIZE
53
54 extern LIST_HEAD(veriexec_devhead, veriexec_dev_list) veriexec_dev_head;
55
56 static int
57 md5_fingerprint(struct vnode *vp, struct veriexec_inode_list *ip,
58 struct proc *p, u_quad_t file_size, char *fingerprint);
59
60 static int
61 sha1_fingerprint(struct vnode *vp, struct veriexec_inode_list *ip,
62 struct proc *p, u_quad_t file_size, char *fingerprint);
63
64
65 /*
66 * md5_fingerprint:
67 * Evaluate the md5 fingerprint of the given file.
68 *
69 */
70 static int
71 md5_fingerprint(struct vnode *vp, struct veriexec_inode_list *ip,
72 struct proc *p, u_quad_t file_size, char *fingerprint)
73 {
74 u_quad_t j;
75 MD5_CTX md5context;
76 char *filebuf;
77 size_t resid;
78 int count, error;
79
80 filebuf = malloc(BUF_SIZE, M_TEMP, M_WAITOK);
81 MD5Init(&md5context);
82
83 for (j = 0; j < file_size; j+= BUF_SIZE) {
84 if ((j + BUF_SIZE) > file_size) {
85 count = file_size - j;
86 } else
87 count = BUF_SIZE;
88
89 error = vn_rdwr(UIO_READ, vp, filebuf, count, j,
90 UIO_SYSSPACE, 0, p->p_ucred, &resid, p);
91
92 if (error) {
93 free(filebuf, M_TEMP);
94 return error;
95 }
96
97 MD5Update(&md5context, filebuf, (unsigned int) count);
98
99 }
100
101 MD5Final(fingerprint, &md5context);
102 free(filebuf, M_TEMP);
103 return 0;
104 }
105
106 static int
107 sha1_fingerprint(struct vnode *vp, struct veriexec_inode_list *ip,
108 struct proc *p, u_quad_t file_size, char *fingerprint)
109 {
110 u_quad_t j;
111 SHA1_CTX sha1context;
112 char *filebuf;
113 size_t resid;
114 int count, error;
115
116 filebuf = malloc(BUF_SIZE, M_TEMP, M_WAITOK);
117 SHA1Init(&sha1context);
118
119 for (j = 0; j < file_size; j+= BUF_SIZE) {
120 if ((j + BUF_SIZE) > file_size) {
121 count = file_size - j;
122 } else
123 count = BUF_SIZE;
124
125 error = vn_rdwr(UIO_READ, vp, filebuf, count, j,
126 UIO_SYSSPACE, 0, p->p_ucred, &resid, p);
127
128 if (error) {
129 free(filebuf, M_TEMP);
130 return error;
131 }
132
133 SHA1Update(&sha1context, filebuf, (unsigned int) count);
134
135 }
136
137 SHA1Final(fingerprint, &sha1context);
138 free(filebuf, M_TEMP);
139 return 0;
140 }
141
142 /*
143 * evaluate_fingerprint:
144 * Check the fingerprint type for the given file and evaluate the
145 * fingerprint for that file. It is assumed that fingerprint has sufficient
146 * storage to hold the resulting fingerprint string.
147 *
148 */
149 int
150 evaluate_fingerprint(struct vnode *vp, struct veriexec_inode_list *ip,
151 struct proc *p, u_quad_t file_size, char *fingerprint)
152 {
153 int error;
154
155 switch (ip->fp_type) {
156 case FINGERPRINT_TYPE_MD5:
157 error = md5_fingerprint(vp, ip, p, file_size, fingerprint);
158 break;
159
160 case FINGERPRINT_TYPE_SHA1:
161 error = sha1_fingerprint(vp, ip, p, file_size, fingerprint);
162 break;
163
164 default:
165 error = EINVAL;
166 break;
167 }
168
169 return error;
170 }
171
172 /*
173 * fingerprintcmp:
174 * Compare the two given fingerprints to see if they are the same
175 * Differing fingerprint methods may have differing lengths which
176 * is handled by this routine. This function follows the convention
177 * of other cmp functions and returns 0 if the fingerprints match and
178 * 1 if they don't.
179 */
180 int
181 fingerprintcmp(struct veriexec_inode_list *ip, unsigned char *digest)
182 {
183 switch(ip->fp_type) {
184 case FINGERPRINT_TYPE_MD5:
185 return memcmp(ip->fingerprint, digest, MD5_FINGERPRINTLEN);
186 break;
187
188 case FINGERPRINT_TYPE_SHA1:
189 return memcmp(ip->fingerprint, digest, SHA1_FINGERPRINTLEN);
190 break;
191
192 default:
193 /* unknown fingerprint type, just fail it after whining */
194 printf("fingerprintcmp: unknown fingerprint type\n");
195 return 1;
196 break;
197 }
198 }
199
200
201 /*
202 * get_veriexec_inode:
203 * Search the given verified exec fingerprint list for the given
204 * fileid. If it exists then return a pointer to the list entry,
205 * otherwise return NULL. If found_dev is non-NULL set this to true
206 * iff the given device has a fingerprint list.
207 *
208 */
209 struct veriexec_inode_list *
210 get_veriexec_inode(struct veriexec_devhead *head, long fsid, long fileid,
211 char *found_dev)
212 {
213 struct veriexec_dev_list *lp;
214 struct veriexec_inode_list *ip;
215
216 ip = NULL;
217 if (found_dev != NULL)
218 *found_dev = 0;
219
220 #ifdef VERIFIED_EXEC_DEBUG
221 printf("searching for file %lu on device %lu\n", fileid, fsid);
222 #endif
223
224 for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries))
225 if (lp->id == fsid)
226 break;
227
228 if (lp != NULL) {
229 #ifdef VERIFIED_EXEC_DEBUG
230 printf("found matching dev number %lu\n", lp->id);
231 #endif
232 if (found_dev != NULL)
233 *found_dev = 1;
234
235 for (ip = LIST_FIRST(&(lp->inode_head)); ip != NULL;
236 ip = LIST_NEXT(ip, entries))
237 if (ip->inode == fileid)
238 break;
239 }
240
241 return ip;
242 }
243
244 /*
245 * check veriexec:
246 * check a file signature and return a status to check_exec.
247 */
248 int
249 check_veriexec(struct proc *p, struct vnode *vp, struct exec_package *epp,
250 int direct_exec)
251 {
252 int error;
253 char digest[MAXFINGERPRINTLEN], found_dev;
254 struct veriexec_inode_list *ip;
255
256 error = 0;
257 found_dev = 0;
258 if (vp->fp_status == FINGERPRINT_INVALID) {
259
260 #ifdef VERIFIED_EXEC_DEBUG
261 printf("looking for loaded signature\n");
262 #endif
263 ip = get_veriexec_inode(&veriexec_dev_head, epp->ep_vap->va_fsid,
264 epp->ep_vap->va_fileid, &found_dev);
265
266 if (found_dev == 0) {
267 #ifdef VERIFIED_EXEC_DEBUG
268 printf("No device entry found\n");
269 #endif
270 vp->fp_status = FINGERPRINT_NODEV;
271 }
272
273 if (ip != NULL) {
274 #ifdef VERIFIED_EXEC_DEBUG
275 printf("found matching inode number %lu\n", ip->inode);
276 #endif
277 error = evaluate_fingerprint(vp, ip, p,
278 epp->ep_vap->va_size,
279 digest);
280 if (error)
281 return error;
282
283 if (fingerprintcmp(ip, digest) == 0) {
284 if (ip->type == VERIEXEC_DIRECT) {
285 #ifdef VERIFIED_EXEC_DEBUG
286 printf("Evaluated fingerprint matches\n");
287 #endif
288 vp->fp_status = FINGERPRINT_VALID;
289 } else {
290 #ifdef VERIFIED_EXEC_DEBUG
291 printf("Evaluated indirect fingerprint matches\n");
292 #endif
293 vp->fp_status = FINGERPRINT_INDIRECT;
294 }
295 } else {
296 #ifdef VERIFIED_EXEC_DEBUG
297 printf("Evaluated fingerprint match failed\n");
298 #endif
299 vp->fp_status = FINGERPRINT_NOMATCH;
300 }
301 } else {
302 #ifdef VERIFIED_EXEC_DEBUG
303 printf("No fingerprint entry found\n");
304 #endif
305 vp->fp_status = FINGERPRINT_NOENTRY;
306 }
307 }
308
309 switch (vp->fp_status) {
310 case FINGERPRINT_INVALID: /* should not happen */
311 printf("Got unexpected FINGERPRINT_INVALID!!!\n");
312 error = EPERM;
313 break;
314 case FINGERPRINT_VALID: /* is ok - report so if debug is on */
315 #ifdef VERIFIED_EXEC_DEBUG
316 printf("Fingerprint matches\n");
317 #endif
318 break;
319
320 case FINGERPRINT_INDIRECT: /* fingerprint ok but need to check
321 for direct execution */
322 if (direct_exec == 1) {
323 printf("Attempt to execute %s (dev %lu, inode %lu) "
324 "directly by pid %u (ppid %u, gppid %u)\n",
325 epp->ep_name, epp->ep_vap->va_fsid,
326 epp->ep_vap->va_fileid, p->p_pid,
327 p->p_pptr->p_pid, p->p_pptr->p_pptr->p_pid);
328 if (securelevel > 1)
329 error = EPERM;
330 }
331 break;
332
333 case FINGERPRINT_NOMATCH: /* does not match - whine about it */
334 printf("Fingerprint for %s (dev %lu, inode %lu) does not "
335 "match loaded value\n",
336 epp->ep_name, epp->ep_vap->va_fsid,
337 epp->ep_vap->va_fileid);
338 if (securelevel > 1)
339 error = EPERM;
340 break;
341
342 case FINGERPRINT_NOENTRY: /* no entry in the list, complain */
343 printf("No fingerprint for %s (dev %lu, inode %lu)\n",
344 epp->ep_name, epp->ep_vap->va_fsid,
345 epp->ep_vap->va_fileid);
346 if (securelevel > 1)
347 error = EPERM;
348 break;
349
350 case FINGERPRINT_NODEV: /* no signatures for the device, complain */
351 #ifdef VERIFIED_EXEC_DEBUG
352 printf("No signatures for device %lu\n",
353 epp->ep_vap->va_fsid);
354 #endif
355 if (securelevel > 1)
356 error = EPERM;
357 break;
358
359 default: /* this should never happen. */
360 printf("Invalid fp_status field for vnode %p\n", vp);
361 error = EPERM;
362 }
363
364 return error;
365
366 }
Cache object: 78e818b397187edf57d57dd02e2cb545
|