]> git.proxmox.com Git - grub2.git/blob - grub-core/commands/verifiers.c
Import grub2_2.04.orig.tar.xz
[grub2.git] / grub-core / commands / verifiers.c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2017 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Verifiers helper.
19 */
20
21 #include <grub/file.h>
22 #include <grub/verify.h>
23 #include <grub/dl.h>
24
25 GRUB_MOD_LICENSE ("GPLv3+");
26
27 struct grub_file_verifier *grub_file_verifiers;
28
29 struct grub_verified
30 {
31 grub_file_t file;
32 void *buf;
33 };
34 typedef struct grub_verified *grub_verified_t;
35
36 static void
37 verified_free (grub_verified_t verified)
38 {
39 if (verified)
40 {
41 grub_free (verified->buf);
42 grub_free (verified);
43 }
44 }
45
46 static grub_ssize_t
47 verified_read (struct grub_file *file, char *buf, grub_size_t len)
48 {
49 grub_verified_t verified = file->data;
50
51 grub_memcpy (buf, (char *) verified->buf + file->offset, len);
52 return len;
53 }
54
55 static grub_err_t
56 verified_close (struct grub_file *file)
57 {
58 grub_verified_t verified = file->data;
59
60 grub_file_close (verified->file);
61 verified_free (verified);
62 file->data = 0;
63
64 /* Device and name are freed by parent. */
65 file->device = 0;
66 file->name = 0;
67
68 return grub_errno;
69 }
70
71 struct grub_fs verified_fs =
72 {
73 .name = "verified_read",
74 .fs_read = verified_read,
75 .fs_close = verified_close
76 };
77
78 static grub_file_t
79 grub_verifiers_open (grub_file_t io, enum grub_file_type type)
80 {
81 grub_verified_t verified = NULL;
82 struct grub_file_verifier *ver;
83 void *context;
84 grub_file_t ret = 0;
85 grub_err_t err;
86 int defer = 0;
87
88 grub_dprintf ("verify", "file: %s type: %d\n", io->name, type);
89
90 if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_SIGNATURE
91 || (type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_VERIFY_SIGNATURE
92 || (type & GRUB_FILE_TYPE_SKIP_SIGNATURE))
93 return io;
94
95 if (io->device->disk &&
96 (io->device->disk->dev->id == GRUB_DISK_DEVICE_MEMDISK_ID
97 || io->device->disk->dev->id == GRUB_DISK_DEVICE_PROCFS_ID))
98 return io;
99
100 FOR_LIST_ELEMENTS(ver, grub_file_verifiers)
101 {
102 enum grub_verify_flags flags = 0;
103 err = ver->init (io, type, &context, &flags);
104 if (err)
105 goto fail_noclose;
106 if (flags & GRUB_VERIFY_FLAGS_DEFER_AUTH)
107 {
108 defer = 1;
109 continue;
110 }
111 if (!(flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION))
112 break;
113 }
114
115 if (!ver)
116 {
117 if (defer)
118 {
119 grub_error (GRUB_ERR_ACCESS_DENIED,
120 N_("verification requested but nobody cares: %s"), io->name);
121 goto fail_noclose;
122 }
123
124 /* No verifiers wanted to verify. Just return underlying file. */
125 return io;
126 }
127
128 ret = grub_malloc (sizeof (*ret));
129 if (!ret)
130 {
131 goto fail;
132 }
133 *ret = *io;
134
135 ret->fs = &verified_fs;
136 ret->not_easily_seekable = 0;
137 if (ret->size >> (sizeof (grub_size_t) * GRUB_CHAR_BIT - 1))
138 {
139 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
140 N_("big file signature isn't implemented yet"));
141 goto fail;
142 }
143 verified = grub_malloc (sizeof (*verified));
144 if (!verified)
145 {
146 goto fail;
147 }
148 verified->buf = grub_malloc (ret->size);
149 if (!verified->buf)
150 {
151 goto fail;
152 }
153 if (grub_file_read (io, verified->buf, ret->size) != (grub_ssize_t) ret->size)
154 {
155 if (!grub_errno)
156 grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
157 io->name);
158 goto fail;
159 }
160
161 err = ver->write (context, verified->buf, ret->size);
162 if (err)
163 goto fail;
164
165 err = ver->fini ? ver->fini (context) : GRUB_ERR_NONE;
166 if (err)
167 goto fail;
168
169 if (ver->close)
170 ver->close (context);
171
172 FOR_LIST_ELEMENTS_NEXT(ver, grub_file_verifiers)
173 {
174 enum grub_verify_flags flags = 0;
175 err = ver->init (io, type, &context, &flags);
176 if (err)
177 goto fail_noclose;
178 if (flags & GRUB_VERIFY_FLAGS_SKIP_VERIFICATION ||
179 /* Verification done earlier. So, we are happy here. */
180 flags & GRUB_VERIFY_FLAGS_DEFER_AUTH)
181 continue;
182 err = ver->write (context, verified->buf, ret->size);
183 if (err)
184 goto fail;
185
186 err = ver->fini ? ver->fini (context) : GRUB_ERR_NONE;
187 if (err)
188 goto fail;
189
190 if (ver->close)
191 ver->close (context);
192 }
193
194 verified->file = io;
195 ret->data = verified;
196 return ret;
197
198 fail:
199 ver->close (context);
200 fail_noclose:
201 verified_free (verified);
202 grub_free (ret);
203 return NULL;
204 }
205
206 grub_err_t
207 grub_verify_string (char *str, enum grub_verify_string_type type)
208 {
209 struct grub_file_verifier *ver;
210 FOR_LIST_ELEMENTS(ver, grub_file_verifiers)
211 {
212 grub_err_t err;
213 err = ver->verify_string ? ver->verify_string (str, type) : GRUB_ERR_NONE;
214 if (err)
215 return err;
216 }
217 return GRUB_ERR_NONE;
218 }
219
220 GRUB_MOD_INIT(verifiers)
221 {
222 grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open);
223 }
224
225 GRUB_MOD_FINI(verifiers)
226 {
227 grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY);
228 }