status_t linux_init (vmi_instance_t vmi) { status_t ret = VMI_FAILURE; if (vmi->cr3){ vmi->kpgd = vmi->cr3; } else if (VMI_SUCCESS == linux_system_map_symbol_to_address(vmi, "swapper_pg_dir", &vmi->kpgd)){ dbprint("--got vaddr for swapper_pg_dir (0x%.16llx).\n", vmi->kpgd); if (driver_is_pv(vmi)){ vmi->kpgd = vmi_translate_kv2p(vmi, vmi->kpgd); if (vmi_read_addr_pa(vmi, vmi->kpgd, &(vmi->kpgd)) == VMI_FAILURE){ errprint("Failed to get physical addr for kpgd.\n"); goto _exit; } } else{ vmi->kpgd = vmi_translate_kv2p(vmi, vmi->kpgd); } } else{ errprint("swapper_pg_dir not found and CR3 not set, exiting\n"); goto _exit; } vmi->kpgd = vmi->cr3; dbprint("**set vmi->kpgd (0x%.16llx).\n", vmi->kpgd); addr_t address = vmi_translate_ksym2v(vmi, "init_task"); address += vmi->os.linux_instance.tasks_offset; if (VMI_FAILURE == vmi_read_addr_va(vmi, address, 0, &(vmi->init_task))){ errprint("Failed to get task list head 'init_task'.\n"); goto _exit; } ret = VMI_SUCCESS; _exit: return ret; }
/* * check that this vm uses a paging method that we support * and set pm/cr3/pae/pse/lme flags optionally on the given pointers */ status_t probe_memory_layout_x86(vmi_instance_t vmi) { // To get the paging layout, the following bits are needed: // 1. CR0.PG // 2. CR4.PAE // 3. Either (a) IA32_EFER.LME, or (b) the guest's address width (32 or // 64). Not all backends allow us to read an MSR; in particular, Xen's PV // backend doessn't. status_t ret = VMI_FAILURE; page_mode_t pm = VMI_PM_UNKNOWN; uint8_t dom_addr_width = 0; // domain address width (bytes) /* pull info from registers, if we can */ reg_t cr0, cr3, cr4, efer; int pae = 0, pse = 0, lme = 0; uint8_t msr_efer_lme = 0; // LME bit in MSR_EFER /* get the control register values */ if (driver_get_vcpureg(vmi, &cr0, CR0, 0) == VMI_FAILURE) { errprint("**failed to get CR0\n"); goto _exit; } /* PG Flag --> CR0, bit 31 == 1 --> paging enabled */ if (!VMI_GET_BIT(cr0, 31)) { dbprint(VMI_DEBUG_CORE, "Paging disabled for this VM, only physical addresses supported.\n"); vmi->page_mode = VMI_PM_UNKNOWN; vmi->pae = 0; vmi->pse = 0; vmi->lme = 0; ret = VMI_SUCCESS; goto _exit; } // // Paging enabled (PG==1) // if (driver_get_vcpureg(vmi, &cr4, CR4, 0) == VMI_FAILURE) { errprint("**failed to get CR4\n"); goto _exit; } /* PSE Flag --> CR4, bit 5 */ pae = VMI_GET_BIT(cr4, 5); dbprint(VMI_DEBUG_CORE, "**set pae = %d\n", pae); /* PSE Flag --> CR4, bit 4 */ pse = VMI_GET_BIT(cr4, 4); dbprint(VMI_DEBUG_CORE, "**set pse = %d\n", pse); ret = driver_get_vcpureg(vmi, &efer, MSR_EFER, 0); if (VMI_SUCCESS == ret) { lme = VMI_GET_BIT(efer, 8); dbprint(VMI_DEBUG_CORE, "**set lme = %d\n", lme); } else { dbprint(VMI_DEBUG_CORE, "**failed to get MSR_EFER, trying method #2\n"); // does this trick work in all cases? ret = driver_get_address_width(vmi, &dom_addr_width); if (VMI_FAILURE == ret) { errprint ("Failed to get domain address width. Giving up.\n"); goto _exit; } lme = (8 == dom_addr_width); dbprint (VMI_DEBUG_CORE, "**found guest address width is %d bytes; assuming IA32_EFER.LME = %d\n", dom_addr_width, lme); } // if // Get current cr3 for sanity checking if (driver_get_vcpureg(vmi, &cr3, CR3, 0) == VMI_FAILURE) { errprint("**failed to get CR3\n"); goto _exit; } // now determine addressing mode if (0 == pae) { dbprint(VMI_DEBUG_CORE, "**32-bit paging\n"); pm = VMI_PM_LEGACY; cr3 &= 0xFFFFF000ull; } // PAE == 1; determine IA-32e or PAE else if (lme) { // PAE == 1, LME == 1 dbprint(VMI_DEBUG_CORE, "**IA-32e paging\n"); pm = VMI_PM_IA32E; cr3 &= 0xFFFFFFFFFFFFF000ull; } else { // PAE == 1, LME == 0 dbprint(VMI_DEBUG_CORE, "**PAE paging\n"); pm = VMI_PM_PAE; cr3 &= 0xFFFFFFE0; } // if-else dbprint(VMI_DEBUG_CORE, "**sanity checking cr3 = 0x%.16"PRIx64"\n", cr3); /* testing to see CR3 value */ if (!driver_is_pv(vmi) && cr3 >= vmi->max_physical_address) { // sanity check on CR3 dbprint(VMI_DEBUG_CORE, "** Note cr3 value [0x%"PRIx64"] exceeds memsize [0x%"PRIx64"]\n", cr3, vmi->size); } vmi->page_mode = pm; vmi->pae = pae; vmi->pse = pse; vmi->lme = lme; _exit: return ret; }
status_t linux_init(vmi_instance_t vmi) { status_t ret = VMI_FAILURE; os_interface_t os_interface = NULL; if (vmi->config == NULL) { errprint("VMI_ERROR: No config table found\n"); return VMI_FAILURE; } if (vmi->os_data != NULL) { errprint("VMI_ERROR: os data already initialized, reinitializing\n"); free(vmi->os_data); } vmi->os_data = safe_malloc(sizeof(struct linux_instance)); bzero(vmi->os_data, sizeof(struct linux_instance)); g_hash_table_foreach(vmi->config, (GHFunc)linux_read_config_ghashtable_entries, vmi); if (VMI_SUCCESS == linux_system_map_symbol_to_address(vmi, "swapper_pg_dir", NULL, &vmi->kpgd)) { dbprint("--got vaddr for swapper_pg_dir (0x%.16"PRIx64").\n", vmi->kpgd); if (driver_is_pv(vmi)) { vmi->kpgd = vmi_translate_kv2p(vmi, vmi->kpgd); if (vmi_read_addr_pa(vmi, vmi->kpgd, &(vmi->kpgd)) == VMI_FAILURE) { errprint( "Failed to get physical addr for kpgd using swapper_pg_dir.\n"); } } } if (!vmi->kpgd) { ret = driver_get_vcpureg(vmi, &vmi->kpgd, CR3, 0); if (ret != VMI_SUCCESS) { errprint( "Driver does not support cr3 read and kpgd could not be set, exiting\n"); goto _exit; } } dbprint("**set vmi->kpgd (0x%.16"PRIx64").\n", vmi->kpgd); ret = linux_system_map_symbol_to_address(vmi, "init_task", NULL, &vmi->init_task); if (ret != VMI_SUCCESS) { errprint("VMI_ERROR: Could not get init_task from System.map\n"); return ret; } os_interface = safe_malloc(sizeof(struct os_interface)); bzero(os_interface, sizeof(struct os_interface)); os_interface->os_get_offset = linux_get_offset; os_interface->os_pid_to_pgd = linux_pid_to_pgd; os_interface->os_pgd_to_pid = linux_pgd_to_pid; os_interface->os_ksym2v = linux_system_map_symbol_to_address; os_interface->os_usym2rva = NULL; os_interface->os_rva2sym = NULL; os_interface->os_teardown = linux_teardown; vmi->os_interface = os_interface; _exit: return ret; }