xref: /freebsd/lib/libsecureboot/pass_manifest.c (revision 81ad6265)
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  * $FreeBSD$
27  */
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/stat.h>
32 
33 #include "libsecureboot-priv.h"
34 #include <verify_file.h>
35 
36 /*
37  * Values to pass to kernel by envs.
38  */
39 static char manifest_path[MAXPATHLEN];
40 static char manifest_prefix[MAXPATHLEN];
41 static char manifest_hash[2 * br_sha256_SIZE + 2];
42 static int manifest_present = 0;
43 
44 /*
45  * Verify and pass manifest path and digest to kernel through envs.
46  * The paths in manifest can be either absolute,
47  * or "prefix", if exists will be added to the ones that are not.
48  */
49 int
50 pass_manifest(const char *path, const char *prefix)
51 {
52 	char *content;
53 	struct stat st;
54 	unsigned char digest[br_sha256_SIZE];
55 	const br_hash_class *md;
56 	br_hash_compat_context ctx;
57 	int rc;
58 
59 	content = NULL;
60 	md = &br_sha256_vtable;
61 
62 	if (strnlen(path, MAXPATHLEN) == MAXPATHLEN ||
63 	    strnlen(prefix, MAXPATHLEN) == MAXPATHLEN)
64 		return (EINVAL);
65 
66 	rc = stat(path, &st);
67 	if (rc != 0)
68 		goto out;
69 
70 	if (!S_ISREG(st.st_mode)) {
71 		rc = EINVAL;
72 		goto out;
73 	}
74 
75 	rc = is_verified(&st);
76 
77 	if (rc != VE_NOT_CHECKED && rc != VE_VERIFIED) {
78 		rc = EPERM;
79 		goto out;
80 	}
81 
82 	if (rc == VE_VERIFIED)
83 		content = read_file(path, NULL);
84 	else
85 		content = (char *)verify_signed(path, VEF_VERBOSE);
86 
87 	if (content == NULL) {
88 		add_verify_status(&st, VE_FINGERPRINT_WRONG);
89 		rc = EIO;
90 		goto out;
91 	}
92 
93 	add_verify_status(&st, VE_VERIFIED);
94 
95 	md->init(&ctx.vtable);
96 	md->update(&ctx.vtable, content, st.st_size);
97 	md->out(&ctx.vtable, digest);
98 
99 	if (prefix == NULL)
100 		manifest_prefix[0] = '\0';
101 	else
102 		strcpy(manifest_prefix, prefix);
103 
104 	strcpy(manifest_path, path);
105 
106 	hexdigest(manifest_hash, 2 * br_sha256_SIZE + 2,
107 	    digest, br_sha256_SIZE);
108 	manifest_hash[2*br_sha256_SIZE] = '\0';
109 
110 	manifest_present = 1;
111 	rc = 0;
112 
113 out:
114 	if (content != NULL)
115 		free(content);
116 
117 	return (rc);
118 }
119 
120 /*
121  * Set appropriate envs to inform kernel about manifest location and digest.
122  * This should be called right before boot so that envs can't be replaced.
123  */
124 int
125 pass_manifest_export_envs()
126 {
127 	int rc;
128 
129 	/* If we have nothing to pass make sure that envs are empty. */
130 	if (!manifest_present) {
131 		unsetenv("veriexec.manifest_path");
132 		unsetenv("veriexec.manifest_hash");
133 		unsetenv("veriexec.manifest_prefix");
134 		return (0);
135 	}
136 
137 	rc = setenv("veriexec.manifest_path", manifest_path, 1);
138 	if (rc != 0)
139 		return (rc);
140 
141 	rc = setenv("veriexec.manifest_hash", manifest_hash, 1);
142 	if (rc != 0) {
143 		unsetenv("veriexec.manifest_path");
144 		return (rc);
145 	}
146 
147 	if (manifest_prefix[0] != '\0')
148 		rc = setenv("veriexec.manifest_prefix", manifest_prefix, 1);
149 
150 	return (rc);
151 }
152 
153