]>
git.proxmox.com Git - efi-boot-shim.git/blob - sbat.c
1 // SPDX-License-Identifier: BSD-2-Clause-Patent
3 * sbat.c - parse SBAT data from the .sbat section data
10 get_sbat_field(CHAR8
*current
, CHAR8
*end
, const CHAR8
**field
, char delim
)
14 if (!field
|| !current
|| !end
|| current
>= end
)
17 offset
= strchrnula(current
, delim
);
20 if (!offset
|| !*offset
)
28 parse_sbat_entry(CHAR8
**current
, CHAR8
*end
, struct sbat_entry
**sbat_entry
)
30 struct sbat_entry
*entry
= NULL
;
32 entry
= AllocateZeroPool(sizeof(*entry
));
34 return EFI_OUT_OF_RESOURCES
;
36 *current
= get_sbat_field(*current
, end
, &entry
->component_name
, ',');
37 if (!entry
->component_name
)
40 *current
= get_sbat_field(*current
, end
, &entry
->component_generation
,
42 if (!entry
->component_generation
)
45 *current
= get_sbat_field(*current
, end
, &entry
->vendor_name
, ',');
46 if (!entry
->vendor_name
)
50 get_sbat_field(*current
, end
, &entry
->vendor_package_name
, ',');
51 if (!entry
->vendor_package_name
)
54 *current
= get_sbat_field(*current
, end
, &entry
->vendor_version
, ',');
55 if (!entry
->vendor_version
)
58 *current
= get_sbat_field(*current
, end
, &entry
->vendor_url
, '\n');
59 if (!entry
->vendor_url
)
68 return EFI_INVALID_PARAMETER
;
72 cleanup_sbat_entries(size_t n
, struct sbat_entry
**entries
)
79 for (i
= 0; i
< n
; i
++) {
89 parse_sbat(char *sbat_base
, size_t sbat_size
, size_t *sbats
, struct sbat_entry
***sbat
)
91 CHAR8
*current
= (CHAR8
*)sbat_base
;
92 CHAR8
*end
= (CHAR8
*)sbat_base
+ sbat_size
;
93 EFI_STATUS efi_status
= EFI_SUCCESS
;
94 struct sbat_entry
*entry
= NULL
;
95 struct sbat_entry
**entries
;
98 size_t n
= PAGE_SIZE
/ sizeof(*entry
);
100 if (!sbat_base
|| sbat_size
== 0 || !sbats
|| !sbat
)
101 return EFI_INVALID_PARAMETER
;
104 return EFI_INVALID_PARAMETER
;
109 entries
= AllocateZeroPool(pages
* PAGE_SIZE
);
111 return EFI_OUT_OF_RESOURCES
;
115 efi_status
= parse_sbat_entry(¤t
, end
, &entry
);
116 if (EFI_ERROR(efi_status
))
120 efi_status
= EFI_INVALID_PARAMETER
;
125 struct sbat_entry
**new_entries
;
126 unsigned int osize
= PAGE_SIZE
* pages
;
127 unsigned int nsize
= osize
+ PAGE_SIZE
;
129 new_entries
= ReallocatePool(entries
, osize
, nsize
);
131 efi_status
= EFI_OUT_OF_RESOURCES
;
134 entries
= new_entries
;
135 ZeroMem(&entries
[i
], PAGE_SIZE
);
137 n
= nsize
/ sizeof(entry
);
139 entries
[i
++] = entry
;
140 } while (entry
&& current
&& *current
!= '\0');
147 perror(L
"Failed to parse SBAT data: %r\n", efi_status
);
148 cleanup_sbat_entries(i
, entries
);
153 verify_single_entry(struct sbat_entry
*entry
, struct sbat_var
*sbat_var_entry
)
155 UINT16 sbat_gen
, sbat_var_gen
;
157 if (strcmp(entry
->component_name
, sbat_var_entry
->component_name
) == 0) {
158 dprint(L
"component %a has a matching SBAT variable entry, verifying\n",
159 entry
->component_name
);
162 * atoi returns zero for failed conversion, so essentially
163 * badly parsed component_generation will be treated as zero
165 sbat_gen
= atoi(entry
->component_generation
);
166 sbat_var_gen
= atoi(sbat_var_entry
->component_generation
);
168 if (sbat_gen
< sbat_var_gen
) {
169 dprint(L
"component %a, generation %d, was revoked by SBAT variable",
170 entry
->component_name
, sbat_gen
);
171 LogError(L
"image did not pass SBAT verification\n");
172 return EFI_SECURITY_VIOLATION
;
179 cleanup_sbat_var(list_t
*entries
)
181 list_t
*pos
= NULL
, *tmp
= NULL
;
182 struct sbat_var
*entry
;
184 list_for_each_safe(pos
, tmp
, entries
) {
185 entry
= list_entry(pos
, struct sbat_var
, list
);
186 list_del(&entry
->list
);
188 if (entry
->component_generation
)
189 FreePool((CHAR8
*)entry
->component_name
);
190 if (entry
->component_name
)
191 FreePool((CHAR8
*)entry
->component_generation
);
197 verify_sbat(size_t n
, struct sbat_entry
**entries
)
201 EFI_STATUS efi_status
= EFI_SUCCESS
;
202 struct sbat_var
*sbat_var_entry
;
204 if (list_empty(&sbat_var
)) {
205 dprint(L
"SBAT variable not present\n");
209 for (i
= 0; i
< n
; i
++) {
210 list_for_each(pos
, &sbat_var
) {
211 sbat_var_entry
= list_entry(pos
, struct sbat_var
, list
);
212 efi_status
= verify_single_entry(entries
[i
], sbat_var_entry
);
213 if (EFI_ERROR(efi_status
))
218 dprint(L
"all entries from SBAT section verified\n");
223 is_utf8_bom(CHAR8
*buf
, size_t bufsize
)
225 unsigned char bom
[] = { 0xEF, 0xBB, 0xBF };
227 return CompareMem(buf
, bom
, MIN(sizeof(bom
), bufsize
)) == 0;
230 static struct sbat_var
*
231 new_entry(const CHAR8
*comp_name
, const CHAR8
*comp_gen
)
233 struct sbat_var
*new_entry
= AllocatePool(sizeof(*new_entry
));
238 INIT_LIST_HEAD(&new_entry
->list
);
239 new_entry
->component_name
= comp_name
;
240 new_entry
->component_generation
= comp_gen
;
246 add_entry(list_t
*list
, const CHAR8
*comp_name
, const CHAR8
*comp_gen
)
248 struct sbat_var
*new;
250 new = new_entry(comp_name
, comp_gen
);
252 return EFI_OUT_OF_RESOURCES
;
254 list_add_tail(&new->list
, list
);
259 parse_sbat_var(list_t
*entries
)
263 EFI_STATUS efi_status
;
267 return EFI_INVALID_PARAMETER
;
269 INIT_LIST_HEAD(entries
);
271 efi_status
= get_variable(L
"SBAT", &data
, &datasize
, SHIM_LOCK_GUID
);
272 if (EFI_ERROR(efi_status
)) {
273 LogError(L
"Failed to read SBAT variable\n",
278 CHAR8
*start
= (CHAR8
*)data
;
279 CHAR8
*end
= (CHAR8
*)data
+ datasize
;
280 if (is_utf8_bom(start
, datasize
))
283 dprint(L
"SBAT variable data:\n");
285 while (start
[0] != '\0') {
286 const CHAR8
*fields
[2] = {
289 for (i
= 0; i
< 3; i
++) {
292 * on third iteration we check if we had extra stuff on line while parsing
293 * component_name. If delimeter on 2nd iteration was ',', this means that
294 * we have comments after component_name. get_sbat_field in this if condition
295 * parses comments, if they are present and drops them.
297 if (i
== 2 && start
) {
299 start
= get_sbat_field(start
, end
, &tmp
,
305 /* we do not want to jump to next line and grab stuff from that
307 if ((strchrnula(start
, '\n') - start
+ 1) <=
308 (strchrnula(start
, ',') - start
+ 1)) {
316 start
= get_sbat_field(start
, end
, &tmp
, delim
);
317 /* to be replaced when we have strdupa()
319 fields
[i
] = strndupa(tmp
, strlen(tmp
));
324 dprint(L
"component %a with generation %a\n", fields
[0], fields
[1]);
326 add_entry(entries
, fields
[0], fields
[1]);
327 if (EFI_ERROR(efi_status
))
333 perror(L
"failed to parse SBAT variable\n");
334 cleanup_sbat_var(entries
);
336 return EFI_INVALID_PARAMETER
;
338 // vim:fenc=utf-8:tw=75:noet