xref: /freebsd/lib/libsecureboot/pass_manifest.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1 /*-
2  * Copyright (c) 2019 Stormshield.
3  * Copyright (c) 2019 Semihalf.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 
29 #include <sys/stat.h>
30 
31 #include "libsecureboot-priv.h"
32 #include <verify_file.h>
33 
34 /*
35  * Values to pass to kernel by envs.
36  */
37 static char manifest_path[MAXPATHLEN];
38 static char manifest_prefix[MAXPATHLEN];
39 static char manifest_hash[2 * br_sha256_SIZE + 2];
40 static int manifest_present = 0;
41 
42 /*
43  * Verify and pass manifest path and digest to kernel through envs.
44  * The paths in manifest can be either absolute,
45  * or "prefix", if exists will be added to the ones that are not.
46  */
47 int
48 pass_manifest(const char *path, const char *prefix)
49 {
50 	char *content;
51 	struct stat st;
52 	unsigned char digest[br_sha256_SIZE];
53 	const br_hash_class *md;
54 	br_hash_compat_context ctx;
55 	int rc;
56 
57 	content = NULL;
58 	md = &br_sha256_vtable;
59 
60 	if (strnlen(path, MAXPATHLEN) == MAXPATHLEN ||
61 	    strnlen(prefix, MAXPATHLEN) == MAXPATHLEN)
62 		return (EINVAL);
63 
64 	rc = stat(path, &st);
65 	if (rc != 0)
66 		goto out;
67 
68 	if (!S_ISREG(st.st_mode)) {
69 		rc = EINVAL;
70 		goto out;
71 	}
72 
73 	rc = is_verified(&st);
74 
75 	if (rc != VE_NOT_CHECKED && rc != VE_VERIFIED) {
76 		rc = EPERM;
77 		goto out;
78 	}
79 
80 	if (rc == VE_VERIFIED)
81 		content = read_file(path, NULL);
82 	else
83 		content = (char *)verify_signed(path, VEF_VERBOSE);
84 
85 	if (content == NULL) {
86 		add_verify_status(&st, VE_FINGERPRINT_WRONG);
87 		rc = EIO;
88 		goto out;
89 	}
90 
91 	add_verify_status(&st, VE_VERIFIED);
92 
93 	md->init(&ctx.vtable);
94 	md->update(&ctx.vtable, content, st.st_size);
95 	md->out(&ctx.vtable, digest);
96 
97 	if (prefix == NULL)
98 		manifest_prefix[0] = '\0';
99 	else
100 		strcpy(manifest_prefix, prefix);
101 
102 	strcpy(manifest_path, path);
103 
104 	hexdigest(manifest_hash, 2 * br_sha256_SIZE + 2,
105 	    digest, br_sha256_SIZE);
106 	manifest_hash[2*br_sha256_SIZE] = '\0';
107 
108 	manifest_present = 1;
109 	rc = 0;
110 
111 out:
112 	if (content != NULL)
113 		free(content);
114 
115 	return (rc);
116 }
117 
118 /*
119  * Set appropriate envs to inform kernel about manifest location and digest.
120  * This should be called right before boot so that envs can't be replaced.
121  */
122 int
123 pass_manifest_export_envs()
124 {
125 	int rc;
126 
127 	/* If we have nothing to pass make sure that envs are empty. */
128 	if (!manifest_present) {
129 		unsetenv("veriexec.manifest_path");
130 		unsetenv("veriexec.manifest_hash");
131 		unsetenv("veriexec.manifest_prefix");
132 		return (0);
133 	}
134 
135 	rc = setenv("veriexec.manifest_path", manifest_path, 1);
136 	if (rc != 0)
137 		return (rc);
138 
139 	rc = setenv("veriexec.manifest_hash", manifest_hash, 1);
140 	if (rc != 0) {
141 		unsetenv("veriexec.manifest_path");
142 		return (rc);
143 	}
144 
145 	if (manifest_prefix[0] != '\0')
146 		rc = setenv("veriexec.manifest_prefix", manifest_prefix, 1);
147 
148 	return (rc);
149 }
150 
151