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