1 #include <xen/efi.h>
2 #include <xen/init.h>
3 #include <xen/types.h>
4 #include <xen/lib.h>
5 #include <xen/param.h>
6 #include <xen/sched.h>
7 #include <xen/domain_page.h>
8 #include <xen/iommu.h>
9 #include <xen/acpi.h>
10 #include <xen/pfn.h>
11 #include <asm/fixmap.h>
12 #include <asm/page.h>
13 #include <asm/processor.h>
14 #include <asm/e820.h>
15 #include <asm/tboot.h>
16 #include <asm/setup.h>
17 #include <crypto/vmac.h>
18
19 /* tboot=<physical address of shared page> */
20 static unsigned long __initdata opt_tboot_pa;
21 integer_param("tboot", opt_tboot_pa);
22
23 /* Global pointer to shared data; NULL means no measured launch. */
24 tboot_shared_t *g_tboot_shared;
25
26 static vmac_t domain_mac; /* MAC for all domains during S3 */
27 static vmac_t xenheap_mac; /* MAC for xen heap during S3 */
28 static vmac_t frametable_mac; /* MAC for frame table during S3 */
29
30 /* used by tboot_protect_mem_regions() and/or tboot_parse_dmar_table() */
31 static uint64_t __initdata txt_heap_base, __initdata txt_heap_size;
32 static uint64_t __initdata sinit_base, __initdata sinit_size;
33
34 static bool __ro_after_init is_vtd;
35
36 /*
37 * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE)
38 */
39
40 #define TXT_PUB_CONFIG_REGS_BASE 0xfed30000
41 #define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000
42
43 /* # pages for each config regs space - used by fixmap */
44 #define NR_TXT_CONFIG_PAGES ((TXT_PUB_CONFIG_REGS_BASE - \
45 TXT_PRIV_CONFIG_REGS_BASE) >> PAGE_SHIFT)
46
47 /* offsets from pub/priv config space */
48 #define TXTCR_SINIT_BASE 0x0270
49 #define TXTCR_SINIT_SIZE 0x0278
50 #define TXTCR_HEAP_BASE 0x0300
51 #define TXTCR_HEAP_SIZE 0x0308
52
53 #define SHA1_SIZE 20
54 typedef uint8_t sha1_hash_t[SHA1_SIZE];
55
56 typedef struct __packed {
57 uint32_t version; /* currently 6 */
58 sha1_hash_t bios_acm_id;
59 uint32_t edx_senter_flags;
60 uint64_t mseg_valid;
61 sha1_hash_t sinit_hash;
62 sha1_hash_t mle_hash;
63 sha1_hash_t stm_hash;
64 sha1_hash_t lcp_policy_hash;
65 uint32_t lcp_policy_control;
66 uint32_t rlp_wakeup_addr;
67 uint32_t reserved;
68 uint32_t num_mdrs;
69 uint32_t mdrs_off;
70 uint32_t num_vtd_dmars;
71 uint32_t vtd_dmars_off;
72 } sinit_mle_data_t;
73
tboot_copy_memory(unsigned char * va,uint32_t size,unsigned long pa)74 static void __init tboot_copy_memory(unsigned char *va, uint32_t size,
75 unsigned long pa)
76 {
77 unsigned long map_base = 0;
78 unsigned char *map_addr = NULL;
79 unsigned int i;
80
81 for ( i = 0; i < size; i++ )
82 {
83 if ( map_base != PFN_DOWN(pa + i) )
84 {
85 map_base = PFN_DOWN(pa + i);
86 set_fixmap(FIX_TBOOT_MAP_ADDRESS, map_base << PAGE_SHIFT);
87 map_addr = fix_to_virt(FIX_TBOOT_MAP_ADDRESS);
88 }
89 va[i] = map_addr[pa + i - (map_base << PAGE_SHIFT)];
90 }
91 }
92
tboot_probe(void)93 void __init tboot_probe(void)
94 {
95 tboot_shared_t *tboot_shared;
96 static const uuid_t __initconst tboot_shared_uuid = TBOOT_SHARED_UUID;
97
98 /* Look for valid page-aligned address for shared page. */
99 if ( !opt_tboot_pa || (opt_tboot_pa & ~PAGE_MASK) )
100 return;
101
102 /* Map and check for tboot UUID. */
103 set_fixmap(FIX_TBOOT_SHARED_BASE, opt_tboot_pa);
104 tboot_shared = fix_to_virt(FIX_TBOOT_SHARED_BASE);
105 if ( memcmp(&tboot_shared_uuid, &tboot_shared->uuid, sizeof(uuid_t)) )
106 return;
107
108 /* new tboot_shared (w/ GAS support, integrity, etc.) is not backwards
109 compatible */
110 if ( tboot_shared->version < 4 )
111 {
112 printk("unsupported version of tboot (%u)\n", tboot_shared->version);
113 return;
114 }
115
116 g_tboot_shared = tboot_shared;
117 printk("TBOOT: found shared page at phys addr %#lx:\n", opt_tboot_pa);
118 printk(" version: %d\n", tboot_shared->version);
119 printk(" log_addr: %#x\n", tboot_shared->log_addr);
120 printk(" shutdown_entry: %#x\n", tboot_shared->shutdown_entry);
121 printk(" tboot_base: %#x\n", tboot_shared->tboot_base);
122 printk(" tboot_size: %#x\n", tboot_shared->tboot_size);
123 if ( tboot_shared->version >= 6 )
124 printk(" flags: %#x\n", tboot_shared->flags);
125
126 /* these will be needed by tboot_protect_mem_regions() and/or
127 tboot_parse_dmar_table(), so get them now */
128
129 txt_heap_base = txt_heap_size = sinit_base = sinit_size = 0;
130 /* TXT Heap */
131 tboot_copy_memory((unsigned char *)&txt_heap_base, sizeof(txt_heap_base),
132 TXT_PUB_CONFIG_REGS_BASE + TXTCR_HEAP_BASE);
133 tboot_copy_memory((unsigned char *)&txt_heap_size, sizeof(txt_heap_size),
134 TXT_PUB_CONFIG_REGS_BASE + TXTCR_HEAP_SIZE);
135 /* SINIT */
136 tboot_copy_memory((unsigned char *)&sinit_base, sizeof(sinit_base),
137 TXT_PUB_CONFIG_REGS_BASE + TXTCR_SINIT_BASE);
138 tboot_copy_memory((unsigned char *)&sinit_size, sizeof(sinit_size),
139 TXT_PUB_CONFIG_REGS_BASE + TXTCR_SINIT_SIZE);
140 clear_fixmap(FIX_TBOOT_MAP_ADDRESS);
141 }
142
143 /* definitions from xen/drivers/passthrough/vtd/iommu.h
144 * used to walk through vtd page tables */
145 #define LEVEL_STRIDE (9)
146 #define PTE_NUM (1<<LEVEL_STRIDE)
147 #define dma_pte_present(p) (((p).val & 3) != 0)
148 #define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
149 #define agaw_to_level(val) ((val)+2)
150 struct dma_pte {
151 u64 val;
152 };
153
update_iommu_mac(vmac_ctx_t * ctx,uint64_t pt_maddr,int level)154 static void update_iommu_mac(vmac_ctx_t *ctx, uint64_t pt_maddr, int level)
155 {
156 int i;
157 struct dma_pte *pt_vaddr, *pte;
158 int next_level = level - 1;
159
160 if ( pt_maddr == 0 )
161 return;
162
163 pt_vaddr = (struct dma_pte *)map_domain_page(_mfn(paddr_to_pfn(pt_maddr)));
164 vmac_update((void *)pt_vaddr, PAGE_SIZE, ctx);
165
166 for ( i = 0; i < PTE_NUM; i++ )
167 {
168 pte = &pt_vaddr[i];
169 if ( !dma_pte_present(*pte) )
170 continue;
171
172 if ( next_level >= 1 )
173 update_iommu_mac(ctx, dma_pte_addr(*pte), next_level);
174 }
175
176 unmap_domain_page(pt_vaddr);
177 }
178
179 #define is_page_in_use(page) \
180 (page_state_is(page, inuse) || page_state_is(page, offlining))
181
182 /* Wipe ctx to ensure key is not left in memory. */
wipe_ctx(vmac_ctx_t * ctx)183 static void wipe_ctx(vmac_ctx_t *ctx)
184 {
185 memset(ctx, 0, sizeof(*ctx));
186 /*
187 * Make sure the compiler won't optimize out the memset(), for the local
188 * variable (at the call sites) going out of scope right afterwards.
189 */
190 asm volatile ( "" :: "m" (*ctx) );
191 }
192
tboot_gen_domain_integrity(const uint8_t key[TB_KEY_SIZE],vmac_t * mac)193 static void tboot_gen_domain_integrity(const uint8_t key[TB_KEY_SIZE],
194 vmac_t *mac)
195 {
196 struct domain *d;
197 struct page_info *page;
198 uint8_t nonce[16] = {};
199 vmac_ctx_t ctx;
200
201 vmac_set_key((uint8_t *)key, &ctx);
202 for_each_domain( d )
203 {
204 if ( !(d->options & XEN_DOMCTL_CDF_s3_integrity) )
205 continue;
206 printk("MACing Domain %u\n", d->domain_id);
207
208 nrspin_lock(&d->page_alloc_lock);
209 page_list_for_each(page, &d->page_list)
210 {
211 void *pg = __map_domain_page(page);
212 vmac_update(pg, PAGE_SIZE, &ctx);
213 unmap_domain_page(pg);
214 }
215 nrspin_unlock(&d->page_alloc_lock);
216
217 if ( is_iommu_enabled(d) && is_vtd )
218 {
219 const struct domain_iommu *dio = dom_iommu(d);
220
221 update_iommu_mac(&ctx, dio->arch.vtd.pgd_maddr,
222 agaw_to_level(dio->arch.vtd.agaw));
223 }
224 }
225
226 /* TODO: MAC all shadow / HAP page tables */
227
228 *mac = vmac(NULL, 0, nonce, NULL, &ctx);
229
230 wipe_ctx(&ctx);
231 }
232
tboot_gen_xenheap_integrity(const uint8_t key[TB_KEY_SIZE],vmac_t * mac)233 static void tboot_gen_xenheap_integrity(const uint8_t key[TB_KEY_SIZE],
234 vmac_t *mac)
235 {
236 unsigned long mfn;
237 uint8_t nonce[16] = {};
238 vmac_ctx_t ctx;
239
240 vmac_set_key((uint8_t *)key, &ctx);
241 for ( mfn = 0; mfn < max_page; mfn++ )
242 {
243 struct page_info *page = mfn_to_page(_mfn(mfn));
244
245 if ( !mfn_valid(_mfn(mfn)) )
246 continue;
247 if ( is_xen_fixed_mfn(_mfn(mfn)) )
248 continue; /* skip Xen */
249 if ( (mfn >= PFN_DOWN(g_tboot_shared->tboot_base - 3 * PAGE_SIZE))
250 && (mfn < PFN_UP(g_tboot_shared->tboot_base
251 + g_tboot_shared->tboot_size
252 + 3 * PAGE_SIZE)) )
253 continue; /* skip tboot and its page tables */
254
255 if ( is_page_in_use(page) && is_special_page(page) )
256 vmac_update(mfn_to_virt(mfn), PAGE_SIZE, &ctx);
257 }
258 *mac = vmac(NULL, 0, nonce, NULL, &ctx);
259
260 wipe_ctx(&ctx);
261 }
262
tboot_gen_frametable_integrity(const uint8_t key[TB_KEY_SIZE],vmac_t * mac)263 static void tboot_gen_frametable_integrity(const uint8_t key[TB_KEY_SIZE],
264 vmac_t *mac)
265 {
266 unsigned int sidx, eidx, nidx;
267 unsigned int max_idx = DIV_ROUND_UP(max_pdx, PDX_GROUP_COUNT);
268 uint8_t nonce[16] = {};
269 vmac_ctx_t ctx;
270
271 vmac_set_key((uint8_t *)key, &ctx);
272 for ( sidx = 0; ; sidx = nidx )
273 {
274 eidx = find_next_zero_bit(pdx_group_valid, max_idx, sidx);
275 nidx = find_next_bit(pdx_group_valid, max_idx, eidx);
276 if ( nidx >= max_idx )
277 break;
278 vmac_update((uint8_t *)pdx_to_page(sidx * PDX_GROUP_COUNT),
279 (eidx - sidx) * PDX_GROUP_COUNT * sizeof(*frame_table),
280 &ctx);
281 }
282 vmac_update((uint8_t *)pdx_to_page(sidx * PDX_GROUP_COUNT),
283 (max_pdx - sidx * PDX_GROUP_COUNT) * sizeof(*frame_table),
284 &ctx);
285
286 *mac = vmac(NULL, 0, nonce, NULL, &ctx);
287
288 wipe_ctx(&ctx);
289 }
290
tboot_shutdown(uint32_t shutdown_type)291 void tboot_shutdown(uint32_t shutdown_type)
292 {
293 mfn_t map_base;
294 uint32_t map_size;
295 int err;
296
297 g_tboot_shared->shutdown_type = shutdown_type;
298
299 /* Create identity map for tboot shutdown code. */
300 /* do before S3 integrity because mapping tboot may change xenheap */
301 map_base = maddr_to_mfn(g_tboot_shared->tboot_base);
302 map_size = PFN_UP(g_tboot_shared->tboot_size);
303
304 err = map_pages_to_xen(mfn_to_maddr(map_base), map_base, map_size,
305 __PAGE_HYPERVISOR);
306 if ( err != 0 )
307 {
308 printk("error (%#x) mapping tboot pages (mfns) @ %"PRI_mfn", %#x\n",
309 err, mfn_x(map_base), map_size);
310 return;
311 }
312
313 /* Disable interrupts as early as possible but not prior to */
314 /* calling map_pages_to_xen */
315 local_irq_disable();
316
317 /* if this is S3 then set regions to MAC */
318 if ( shutdown_type == TB_SHUTDOWN_S3 )
319 {
320 unsigned long s, e;
321
322 /*
323 * Xen regions for tboot to MAC. This needs to remain in sync with
324 * remove_xen_ranges().
325 */
326 g_tboot_shared->num_mac_regions = 3;
327 /* S3 resume code (and other real mode trampoline code) */
328 g_tboot_shared->mac_regions[0].start = bootsym_phys(trampoline_start);
329 g_tboot_shared->mac_regions[0].size = trampoline_end - trampoline_start;
330 /* hypervisor .text + .rodata */
331 g_tboot_shared->mac_regions[1].start = (uint64_t)__pa(&_stext);
332 g_tboot_shared->mac_regions[1].size = __2M_rodata_end - _stext;
333 /* hypervisor .data + .bss */
334 g_tboot_shared->mac_regions[2].start = (uint64_t)__pa(&__2M_rwdata_start);
335 g_tboot_shared->mac_regions[2].size = __2M_rwdata_end - __2M_rwdata_start;
336 if ( efi_boot_mem_unused(&s, &e) )
337 {
338 g_tboot_shared->mac_regions[2].size =
339 s - (unsigned long)__2M_rwdata_start;
340 g_tboot_shared->mac_regions[3].start = __pa(e);
341 g_tboot_shared->mac_regions[3].size =
342 (unsigned long)__2M_rwdata_end - e;
343 g_tboot_shared->num_mac_regions = 4;
344 }
345
346 /*
347 * MAC domains and other Xen memory
348 */
349 /* Xen has no better entropy source for MAC key than tboot's */
350 /* MAC domains first in case it perturbs xenheap */
351 tboot_gen_domain_integrity(g_tboot_shared->s3_key, &domain_mac);
352 tboot_gen_frametable_integrity(g_tboot_shared->s3_key, &frametable_mac);
353 tboot_gen_xenheap_integrity(g_tboot_shared->s3_key, &xenheap_mac);
354 }
355
356 /*
357 * Disable CET - tboot may not be built with endbr, and it doesn't support
358 * shadow stacks.
359 */
360 if ( read_cr4() & X86_CR4_CET )
361 {
362 wrmsrl(MSR_S_CET, 0);
363 write_cr4(read_cr4() & ~X86_CR4_CET);
364 }
365
366 /*
367 * During early boot, we can be called by panic before idle_vcpu[0] is
368 * setup, but in that case we don't need to change page tables.
369 */
370 if ( idle_vcpu[0] )
371 write_ptbase(idle_vcpu[0]);
372
373 ((void(*)(void))(unsigned long)g_tboot_shared->shutdown_entry)();
374
375 BUG(); /* should not reach here */
376 }
377
tboot_in_measured_env(void)378 int tboot_in_measured_env(void)
379 {
380 return (g_tboot_shared != NULL);
381 }
382
tboot_protect_mem_regions(void)383 int __init tboot_protect_mem_regions(void)
384 {
385 int rc;
386
387 if ( !tboot_in_measured_env() )
388 return 1;
389
390 /* TXT Heap */
391 if ( txt_heap_base == 0 )
392 return 0;
393 rc = e820_change_range_type(&e820, txt_heap_base,
394 txt_heap_base + txt_heap_size,
395 E820_RESERVED, E820_UNUSABLE);
396 if ( !rc )
397 return 0;
398
399 /* SINIT */
400 if ( sinit_base == 0 )
401 return 0;
402 rc = e820_change_range_type(&e820, sinit_base,
403 sinit_base + sinit_size,
404 E820_RESERVED, E820_UNUSABLE);
405 if ( !rc )
406 return 0;
407
408 /* TXT Private Space */
409 rc = e820_change_range_type(&e820, TXT_PRIV_CONFIG_REGS_BASE,
410 TXT_PRIV_CONFIG_REGS_BASE + NR_TXT_CONFIG_PAGES * PAGE_SIZE,
411 E820_RESERVED, E820_UNUSABLE);
412 if ( !rc )
413 return 0;
414
415 return 1;
416 }
417
tboot_parse_dmar_table(acpi_table_handler dmar_handler)418 int __init cf_check tboot_parse_dmar_table(acpi_table_handler dmar_handler)
419 {
420 int rc;
421 uint64_t size;
422 uint32_t dmar_table_length;
423 unsigned long pa;
424 sinit_mle_data_t sinit_mle_data;
425 void *dmar_table;
426
427 if ( !tboot_in_measured_env() )
428 return acpi_table_parse(ACPI_SIG_DMAR, dmar_handler);
429
430 /* ACPI tables may not be DMA protected by tboot, so use DMAR copy */
431 /* SINIT saved in SinitMleData in TXT heap (which is DMA protected) */
432
433 if ( txt_heap_base == 0 )
434 return 1;
435
436 is_vtd = true;
437
438 /* walk heap to SinitMleData */
439 pa = txt_heap_base;
440 /* skip BiosData */
441 tboot_copy_memory((unsigned char *)&size, sizeof(size), pa);
442 pa += size;
443 /* skip OsMleData */
444 tboot_copy_memory((unsigned char *)&size, sizeof(size), pa);
445 pa += size;
446 /* skip OsSinitData */
447 tboot_copy_memory((unsigned char *)&size, sizeof(size), pa);
448 pa += size;
449 /* now points to SinitMleDataSize; set to SinitMleData */
450 pa += sizeof(uint64_t);
451 tboot_copy_memory((unsigned char *)&sinit_mle_data, sizeof(sinit_mle_data),
452 pa);
453 /* get addr of DMAR table */
454 pa += sinit_mle_data.vtd_dmars_off - sizeof(uint64_t);
455 tboot_copy_memory((unsigned char *)&dmar_table_length,
456 sizeof(dmar_table_length),
457 pa + sizeof(char) * ACPI_NAME_SIZE);
458 dmar_table = xmalloc_bytes(dmar_table_length);
459 if ( !dmar_table )
460 return -ENOMEM;
461 tboot_copy_memory(dmar_table, dmar_table_length, pa);
462 clear_fixmap(FIX_TBOOT_MAP_ADDRESS);
463
464 rc = dmar_handler(dmar_table);
465 xfree(dmar_table);
466
467 return rc;
468 }
469
470 static vmac_t orig_mac, resume_mac;
471
tboot_s3_resume(void)472 int tboot_s3_resume(void)
473 {
474 if ( !tboot_in_measured_env() )
475 return 0;
476
477 /* need to do these in reverse order of shutdown */
478 tboot_gen_xenheap_integrity(g_tboot_shared->s3_key, &resume_mac);
479 orig_mac = xenheap_mac;
480 if ( resume_mac != xenheap_mac )
481 return -1;
482
483 tboot_gen_frametable_integrity(g_tboot_shared->s3_key, &resume_mac);
484 orig_mac = frametable_mac;
485 if ( resume_mac != frametable_mac )
486 return -2;
487
488 tboot_gen_domain_integrity(g_tboot_shared->s3_key, &resume_mac);
489 orig_mac = domain_mac;
490 if ( resume_mac != domain_mac )
491 return -3;
492
493 return 0;
494 }
495
tboot_s3_error(int error)496 void tboot_s3_error(int error)
497 {
498 const char *what = "???";
499
500 BUG_ON(!error || !tboot_in_measured_env());
501
502 switch ( error )
503 {
504 case -1: what = "Xen heap"; break;
505 case -2: what = "frame table"; break;
506 case -3: what = "domains"; break;
507 }
508
509 printk("MAC for %s before S3 is: 0x%08"PRIx64"\n", what, orig_mac);
510 printk("MAC for %s after S3 is: 0x%08"PRIx64"\n", what, resume_mac);
511 panic("Memory integrity was lost on resume (%d)\n", error);
512 }
513
tboot_wake_ap(int apicid,unsigned long sipi_vec)514 int tboot_wake_ap(int apicid, unsigned long sipi_vec)
515 {
516 if ( g_tboot_shared->version >= 6 &&
517 (g_tboot_shared->flags & TB_FLAG_AP_WAKE_SUPPORT) )
518 {
519 g_tboot_shared->ap_wake_addr = sipi_vec;
520 g_tboot_shared->ap_wake_trigger = apicid;
521 return 0;
522 }
523 return 1;
524 }
525
526 /*
527 * Local variables:
528 * mode: C
529 * c-file-style: "BSD"
530 * c-basic-offset: 4
531 * tab-width: 4
532 * indent-tabs-mode: nil
533 * End:
534 */
535