xref: /onnv-gate/usr/src/common/crypto/fips/fips_checksum.c (revision 12929:f2051cc42292)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 
26 #include <fips/fips_checksum.h>
27 
28 
29 #ifdef	_KERNEL
30 #define	FIPS_ALLOC(size)	kmem_alloc(size, KM_SLEEP)
31 #define	FIPS_FREE(buf, size)	kmem_free(buf, size)
32 #define	FIPS_READ_FILE		kobj_read_file
33 #define	ERRLOG0(str)		cmn_err(CE_NOTE, str)
34 #define	ERRLOG1(fmt, arg)	cmn_err(CE_NOTE, fmt, arg)
35 #include <sys/sunddi.h>
36 
37 struct _buf *kobj_open_file(char *name);
38 int kobj_read_file(struct _buf *file, char *buf, uint_t size, uint_t off);
39 #else
40 
41 #define	FIPS_ALLOC(size)	malloc(size)
42 #define	FIPS_FREE(buf, size)	free(buf)
43 #define	FIPS_READ_FILE		fips_read_file
44 #define	ERRLOG0(str)		(void) printf(str)
45 #define	ERRLOG1(fmt, arg)	(void) printf(fmt, arg)
46 #endif
47 
48 #define	NUM_SECTIONS	(sizeof (checked_sec_names) / sizeof (char *))
49 
50 static char *checked_sec_names[] = {
51 	".strtab",
52 	".dynamic",
53 	".compcom",
54 	".comment",
55 	".dynstr",
56 	".shstrtab",
57 	".rela.text",
58 	".rela.data",
59 	".text",
60 	".rodata",
61 	".rodata1",
62 	".data",
63 	".symtab",
64 	".SUNW_ctf",
65 	".bss"
66 };
67 
68 
69 static int
70 #ifdef	_KERNEL
process_section(SHA1_CTX * shactx,Elf64_Shdr * section,struct _buf * file,char * shstrtab)71 process_section(SHA1_CTX *shactx, Elf64_Shdr *section, struct _buf *file,
72     char *shstrtab)
73 #else
74 process_section(SHA1_CTX *shactx, Elf64_Shdr *section, int file,
75     char *shstrtab)
76 #endif
77 {
78 	size_t		size, offs;
79 	char		*name;
80 	int		doit = 0;
81 	char		*buf;
82 	int		i;
83 
84 	size = section->sh_size;
85 	offs = section->sh_offset;
86 	name = shstrtab + section->sh_name;
87 	for (i = 0; i < NUM_SECTIONS; i++) {
88 		if (strncmp(name, checked_sec_names[i],
89 		    strlen(checked_sec_names[i]) + 1) == 0) {
90 			doit++;
91 			break;
92 		}
93 	}
94 
95 	if (!doit) {
96 		return (0);
97 	}
98 
99 	/* hash the size of .bss section */
100 	if (strcmp(name, ".bss") == 0) {
101 		char	szstr[32];
102 		(void) snprintf(szstr, sizeof (szstr), "%ld", size);
103 		SHA1Update(shactx, szstr, strlen(szstr));
104 		return (0);
105 	}
106 
107 
108 	/* hash the contents of the section */
109 	if ((buf = FIPS_ALLOC(size)) == NULL) {
110 		ERRLOG1("Not enough memory for section %s\n", name);
111 		return (-1);
112 	}
113 
114 	if (FIPS_READ_FILE(file, buf, size, offs) < 0) {
115 		FIPS_FREE(buf, size);
116 		return (-2);
117 	}
118 
119 	SHA1Update(shactx, buf, size);
120 
121 	FIPS_FREE(buf, size);
122 
123 	return (0);
124 }
125 
126 int
127 #ifdef	_KERNEL
fips_calc_checksum(struct _buf * file,Elf64_Ehdr * ehdr,char * sha1buf)128 fips_calc_checksum(struct _buf *file, Elf64_Ehdr *ehdr, char *sha1buf)
129 #else
130 fips_calc_checksum(int file, Elf64_Ehdr *ehdr, char *sha1buf)
131 #endif
132 {
133 	unsigned int	size, numsec;
134 	Elf64_Shdr	*shdrs;
135 	Elf64_Shdr	*section;
136 	SHA1_CTX	sha1ctx;
137 	char		*shstrtab;
138 	int		i;
139 
140 	numsec = ehdr->e_shnum;
141 	size = ehdr->e_shentsize * numsec;
142 	if ((shdrs = (Elf64_Shdr *)FIPS_ALLOC(size)) == NULL) {
143 		ERRLOG0("Not enough memory for shdrs\n");
144 		return (FAILURE);
145 	}
146 	if (FIPS_READ_FILE(file, (char *)shdrs, size, ehdr->e_shoff) < 0) {
147 		return (FAILURE);
148 	}
149 
150 	/* Obtain the .shstrtab data buffer */
151 	section = &(shdrs[ehdr->e_shstrndx]);
152 	size = section->sh_size;
153 	if ((shstrtab = (char *)FIPS_ALLOC(size)) == NULL) {
154 		ERRLOG0("Not enough memory for shstrtab\n");
155 		return (FAILURE);
156 	}
157 	if (FIPS_READ_FILE(file, shstrtab, size, section->sh_offset) < 0) {
158 		return (FAILURE);
159 	}
160 
161 	SHA1Init(&sha1ctx);
162 	for (i = 0; i < numsec; i++) {
163 		if (process_section(&sha1ctx, &(shdrs[i]),
164 		    file, shstrtab) < 0) {
165 			return (FAILURE);
166 		}
167 	}
168 	SHA1Final(sha1buf, &sha1ctx);
169 
170 	return (0);
171 }
172 
173 
174 #ifndef	_KERNEL
175 
176 int
fips_read_file(int fd,char * buf,int size,int offs)177 fips_read_file(int fd, char *buf, int size, int offs)
178 {
179 	int	i;
180 
181 	if (lseek(fd, offs, SEEK_SET) == (off_t)(-1)) {
182 		(void) fprintf(stderr,
183 		    "lseek returned an error for file %d\n", fd);
184 		return (-1);
185 	}
186 	while ((i = read(fd, buf, size)) >= 0) {
187 		if (size == i) {
188 			break;
189 		} else {
190 			size -= i;
191 			buf += i;
192 		}
193 	}
194 	if (i < 0) {
195 		(void) fprintf(stderr, "read failed for file %d\n", fd);
196 		return (-2);
197 	}
198 
199 	return (0);
200 }
201 
202 #else
203 
204 static int
get_fips_section(Elf64_Ehdr * ehdr,struct _buf * file,char * expected_checksum)205 get_fips_section(Elf64_Ehdr *ehdr, struct _buf *file, char *expected_checksum)
206 {
207 	unsigned int	shdrssz, shstrtabsz, numsec;
208 	Elf64_Shdr	*shdrs = NULL;
209 	Elf64_Shdr	*section;
210 	char		*shstrtab = NULL;
211 	char		*name;
212 	int		rv = FAILURE;
213 	int		i;
214 
215 	numsec = ehdr->e_shnum;
216 	shdrssz = ehdr->e_shentsize * numsec;
217 	if ((shdrs = (Elf64_Shdr *)FIPS_ALLOC(shdrssz)) == NULL) {
218 		ERRLOG0("Not enough memory for shdrs\n");
219 		return (FAILURE);
220 	}
221 	if (FIPS_READ_FILE(file, (char *)shdrs, shdrssz, ehdr->e_shoff) < 0) {
222 		goto exit;
223 	}
224 
225 	/* Obtain the .shstrtab data buffer */
226 	section = &(shdrs[ehdr->e_shstrndx]);
227 	shstrtabsz = section->sh_size;
228 	if ((shstrtab = (char *)FIPS_ALLOC(shstrtabsz)) == NULL) {
229 		ERRLOG0("Not enough memory for shstrtab\n");
230 		goto exit;
231 	}
232 	if (FIPS_READ_FILE(file, shstrtab, shstrtabsz,
233 	    section->sh_offset) < 0) {
234 		goto exit;
235 	}
236 
237 	for (i = 0; i < numsec; i++) {
238 		section = &shdrs[i];
239 		name = shstrtab + section->sh_name;
240 		/* Get the checksum stored in the .SUNW_fips section */
241 		if (strcmp(name, ".SUNW_fips") == 0) {
242 			if (section->sh_size != SHA1_DIGEST_LENGTH) {
243 				goto exit;
244 			}
245 			if (FIPS_READ_FILE(file, expected_checksum,
246 			    section->sh_size, section->sh_offset) < 0) {
247 				goto exit;
248 			}
249 			rv = 0;
250 			goto exit;
251 		}
252 	}
253 
254 
255 exit:
256 	if (shdrs != NULL) {
257 		FIPS_FREE(shdrs, shdrssz);
258 	}
259 	if (shstrtab != NULL) {
260 		FIPS_FREE(shstrtab, shstrtabsz);
261 	}
262 
263 	return (rv);
264 }
265 
266 
267 int
fips_check_module(char * modname,void * _initaddr)268 fips_check_module(char *modname, void *_initaddr)
269 {
270 	struct modctl	*modctlp = NULL;
271 	struct module	*mp = NULL;
272 	struct _buf	*file;
273 	char		*filename;
274 	Elf64_Ehdr	ehdr;
275 	unsigned int	size, i;
276 	char		sha1buf[SHA1_DIGEST_LENGTH];
277 	char		expected_checksum[SHA1_DIGEST_LENGTH];
278 
279 	modctlp = mod_find_by_filename(NULL, modname);
280 	if (modctlp == NULL) {
281 		ERRLOG1("module with modname %s not found\n", modname);
282 		return (FAILURE);
283 	}
284 	mp = (struct module *)modctlp->mod_mp;
285 	if (mp != NULL && mp->filename != NULL) {
286 		filename = mp->filename;
287 	} else {
288 		/* filename does not exist */
289 		return (FAILURE);
290 	}
291 	if ((mp->text > (char *)_initaddr) ||
292 	    (mp->text + mp->text_size < (char *)_initaddr)) {
293 		ERRLOG1("_init() is not in module %s\n", modname);
294 		return (FAILURE);
295 	}
296 
297 	if ((file = kobj_open_file(filename)) == (struct _buf *)-1) {
298 		ERRLOG1("Cannot open %s\n", filename);
299 		return (FAILURE);
300 	}
301 	/* Read the ELF header */
302 	size =  sizeof (ehdr);
303 	if (kobj_read_file(file, (char *)(&ehdr), size, 0) < 0) {
304 		goto fail_exit;
305 	}
306 
307 	/* check if it is an ELF file */
308 	for (i = 0; i < SELFMAG; i++) {
309 		if (ehdr.e_ident[i] != ELFMAG[i]) {
310 			ERRLOG1("%s not an elf file\n", filename);
311 			goto fail_exit;
312 		}
313 	}
314 
315 	/* check if it is relocatable */
316 	if (ehdr.e_type != ET_REL) {
317 		ERRLOG1("%s isn't a relocatable (ET_REL) "
318 		    "module\n", filename);
319 		goto fail_exit;
320 	}
321 
322 	if (fips_calc_checksum(file, &ehdr, sha1buf) < 0) {
323 		goto fail_exit;
324 	}
325 
326 	if (get_fips_section(&ehdr, file, expected_checksum) < 0) {
327 		goto fail_exit;
328 	}
329 
330 	if (memcmp(sha1buf, expected_checksum, SHA1_DIGEST_LENGTH) != 0) {
331 		goto fail_exit;
332 	}
333 
334 	kobj_close_file(file);
335 
336 	return (SUCCESS);
337 
338 fail_exit:
339 
340 	kobj_close_file(file);
341 
342 	return (FAILURE);
343 
344 }
345 
346 #endif
347