Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

efi/libstub: Measure into CC protocol if TCG2 protocol is absent

To accommodate confidential compute VMs that expose the simplified CC
measurement protocol instead of the full-blown TCG2 one, fall back to
the former if the latter does not exist.

The CC protocol was designed to be used in this manner, which is why the
types and prototypes have been kept the same where possible. So reuse
the existing code, and only deviate from the TCG2 code path where
needed.

Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>

+62 -22
+62 -22
drivers/firmware/efi/libstub/efi-stub-helper.c
··· 194 194 *load_options_size = load_option_unpacked.optional_data_size; 195 195 } 196 196 197 - enum efistub_event { 197 + enum efistub_event_type { 198 198 EFISTUB_EVT_INITRD, 199 199 EFISTUB_EVT_LOAD_OPTIONS, 200 200 EFISTUB_EVT_COUNT, ··· 220 220 }, 221 221 }; 222 222 223 + static_assert(sizeof(efi_tcg2_event_t) == sizeof(efi_cc_event_t)); 224 + 225 + union efistub_event { 226 + efi_tcg2_event_t tcg2_data; 227 + efi_cc_event_t cc_data; 228 + }; 229 + 223 230 struct efistub_measured_event { 224 - efi_tcg2_event_t event_data; 231 + union efistub_event event_data; 225 232 TCG_PCClientTaggedEvent tagged_event __packed; 226 233 }; 227 234 228 235 static efi_status_t efi_measure_tagged_event(unsigned long load_addr, 229 236 unsigned long load_size, 230 - enum efistub_event event) 237 + enum efistub_event_type event) 231 238 { 239 + union { 240 + efi_status_t 241 + (__efiapi *hash_log_extend_event)(void *, u64, efi_physical_addr_t, 242 + u64, const union efistub_event *); 243 + struct { u32 hash_log_extend_event; } mixed_mode; 244 + } method; 232 245 struct efistub_measured_event *evt; 233 246 int size = struct_size(evt, tagged_event.tagged_event_data, 234 247 events[event].event_data_len); 235 248 efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; 236 249 efi_tcg2_protocol_t *tcg2 = NULL; 250 + union efistub_event ev; 237 251 efi_status_t status; 252 + void *protocol; 238 253 239 254 efi_bs_call(locate_protocol, &tcg2_guid, NULL, (void **)&tcg2); 240 255 if (tcg2) { 241 - status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, 242 - (void **)&evt); 243 - if (status != EFI_SUCCESS) 244 - goto fail; 245 - 246 - evt->event_data = (struct efi_tcg2_event){ 256 + ev.tcg2_data = (struct efi_tcg2_event){ 247 257 .event_size = size, 248 - .event_header.header_size = sizeof(evt->event_data.event_header), 258 + .event_header.header_size = sizeof(ev.tcg2_data.event_header), 249 259 .event_header.header_version = EFI_TCG2_EVENT_HEADER_VERSION, 250 260 .event_header.pcr_index = events[event].pcr_index, 251 261 .event_header.event_type = EV_EVENT_TAG, 252 262 }; 263 + protocol = tcg2; 264 + method.hash_log_extend_event = 265 + (void *)efi_table_attr(tcg2, hash_log_extend_event); 266 + } else { 267 + efi_guid_t cc_guid = EFI_CC_MEASUREMENT_PROTOCOL_GUID; 268 + efi_cc_protocol_t *cc = NULL; 253 269 254 - evt->tagged_event = (TCG_PCClientTaggedEvent){ 255 - .tagged_event_id = events[event].event_id, 256 - .tagged_event_data_size = events[event].event_data_len, 270 + efi_bs_call(locate_protocol, &cc_guid, NULL, (void **)&cc); 271 + if (!cc) 272 + return EFI_UNSUPPORTED; 273 + 274 + ev.cc_data = (struct efi_cc_event){ 275 + .event_size = size, 276 + .event_header.header_size = sizeof(ev.cc_data.event_header), 277 + .event_header.header_version = EFI_CC_EVENT_HEADER_VERSION, 278 + .event_header.event_type = EV_EVENT_TAG, 257 279 }; 258 280 259 - memcpy(evt->tagged_event.tagged_event_data, events[event].event_data, 260 - events[event].event_data_len); 261 - 262 - status = efi_call_proto(tcg2, hash_log_extend_event, 0, 263 - load_addr, load_size, &evt->event_data); 264 - efi_bs_call(free_pool, evt); 265 - 281 + status = efi_call_proto(cc, map_pcr_to_mr_index, 282 + events[event].pcr_index, 283 + &ev.cc_data.event_header.mr_index); 266 284 if (status != EFI_SUCCESS) 267 285 goto fail; 268 - return EFI_SUCCESS; 286 + 287 + protocol = cc; 288 + method.hash_log_extend_event = 289 + (void *)efi_table_attr(cc, hash_log_extend_event); 269 290 } 270 291 271 - return EFI_UNSUPPORTED; 292 + status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, (void **)&evt); 293 + if (status != EFI_SUCCESS) 294 + goto fail; 295 + 296 + *evt = (struct efistub_measured_event) { 297 + .event_data = ev, 298 + .tagged_event.tagged_event_id = events[event].event_id, 299 + .tagged_event.tagged_event_data_size = events[event].event_data_len, 300 + }; 301 + 302 + memcpy(evt->tagged_event.tagged_event_data, events[event].event_data, 303 + events[event].event_data_len); 304 + 305 + status = efi_fn_call(&method, hash_log_extend_event, protocol, 0, 306 + load_addr, load_size, &evt->event_data); 307 + efi_bs_call(free_pool, evt); 308 + 309 + if (status == EFI_SUCCESS) 310 + return EFI_SUCCESS; 311 + 272 312 fail: 273 313 efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status); 274 314 return status;