Changeset 69820 in vbox
- Timestamp:
- Nov 24, 2017 11:43:38 AM (7 years ago)
- File:
-
- 1 edited
-
trunk/src/VBox/Debugger/DBGPlugInLinux.cpp (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGPlugInLinux.cpp
r69500 r69820 170 170 * Defined Constants And Macros * 171 171 *********************************************************************************************************************************/ 172 /** First kernel map address for 32bit Linux hosts (__START_KERNEL_map). */ 173 #define LNX32_KERNEL_ADDRESS_START UINT32_C(0xc0000000) 174 /** First kernel map address for 64bit Linux hosts (__START_KERNEL_map). */ 175 #define LNX64_KERNEL_ADDRESS_START UINT64_C(0xffffffff80000000) 172 176 /** Validates a 32-bit linux kernel address */ 173 177 #define LNX32_VALID_ADDRESS(Addr) ((Addr) > UINT32_C(0x80000000) && (Addr) < UINT32_C(0xfffff000)) … … 2412 2416 2413 2417 /** 2418 * Probes for a Linux kernel starting at the given address. 2419 * 2420 * @returns Flag whether something which looks like a valid Linux kernel was found. 2421 * @param pThis The Linux digger data. 2422 * @param pUVM The user mode VM handle. 2423 * @param uAddrStart The address to start scanning at. 2424 * @param cbScan How much to scan. 2425 */ 2426 static bool dbgDiggerLinuxProbeWithAddr(PDBGDIGGERLINUX pThis, PUVM pUVM, RTGCUINTPTR uAddrStart, size_t cbScan) 2427 { 2428 /* 2429 * Look for "Linux version " at the start of the rodata segment. 2430 * Hope that this comes before any message buffer or other similar string. 2431 */ 2432 DBGFADDRESS KernelAddr; 2433 DBGFR3AddrFromFlat(pUVM, &KernelAddr, uAddrStart); 2434 DBGFADDRESS HitAddr; 2435 int rc = DBGFR3MemScan(pUVM, 0, &KernelAddr, cbScan, 1, 2436 g_abLinuxVersion, sizeof(g_abLinuxVersion) - 1, &HitAddr); 2437 if (RT_SUCCESS(rc)) 2438 { 2439 char szTmp[128]; 2440 char const *pszX = &szTmp[sizeof(g_abLinuxVersion) - 1]; 2441 rc = DBGFR3MemReadString(pUVM, 0, &HitAddr, szTmp, sizeof(szTmp)); 2442 if ( RT_SUCCESS(rc) 2443 && ( ( pszX[0] == '2' /* 2.x.y with x in {0..6} */ 2444 && pszX[1] == '.' 2445 && pszX[2] >= '0' 2446 && pszX[2] <= '6') 2447 || ( pszX[0] >= '3' /* 3.x, 4.x, ... 9.x */ 2448 && pszX[0] <= '9' 2449 && pszX[1] == '.' 2450 && pszX[2] >= '0' 2451 && pszX[2] <= '9') 2452 ) 2453 ) 2454 { 2455 pThis->AddrKernelBase = KernelAddr; 2456 pThis->AddrLinuxBanner = HitAddr; 2457 return true; 2458 } 2459 } 2460 2461 return false; 2462 } 2463 2464 /** 2465 * Probes for a Linux kernel which has KASLR enabled. 2466 * 2467 * @returns Flag whether a possible candidate location was found. 2468 * @param pThis The Linux digger data. 2469 * @param pUVM The user mode VM handle. 2470 * @param uAddrKernelStart The first address the kernel is expected at. 2471 */ 2472 static bool dbgDiggerLinuxProbeKaslr(PDBGDIGGERLINUX pThis, PUVM pUVM, RTGCUINTPTR uAddrKernelStart) 2473 { 2474 /** 2475 * With KASLR the kernel is loaded at a different address at each boot making detection 2476 * more difficult for us. 2477 * 2478 * The randomization is done in arch/x86/boot/compressed/kaslr.c:choose_random_location() (as of Nov 2017). 2479 * At the end of the method a random offset is chosen using find_random_virt_addr() which is added to the 2480 * kernel map start in the caller (the start of the kernel depends on the bit size, see LNX32_KERNEL_ADDRESS_START 2481 * and LNX64_KERNEL_ADDRESS_START for 32bit and 64bit kernels respectively). 2482 * The lowest offset possible is LOAD_PHYSICAL_ADDR which is defined in arch/x86/include/asm/boot.h 2483 * using CONFIG_PHYSICAL_START aligned to CONFIG_PHYSICAL_ALIGN. 2484 * The default CONFIG_PHYSICAL_START and CONFIG_PHYSICAL_ALIGN are both 0x1000000 no matter whether a 32bit 2485 * or a 64bit kernel is used. So the lowest offset to the kernel start address is 0x1000000. 2486 * The find_random_virt_addr() the number of possible slots where the kernel can be placed based on the image size 2487 * is calculated using the following formula: 2488 * cSlots = ((KERNEL_IMAGE_SIZE - 0x1000000 (minimum) - image_size) / 0x1000000 (CONFIG_PHYSICAL_ALIGN)) + 1 2489 * 2490 * KERNEL_IMAGE_SIZE is 1GB for 64bit kernels and 512MB for 32bit kernels, so the maximum number of slots (resulting 2491 * in the largest possible offset) can be achieved when image_size (which contains the real size of the kernel image 2492 * which is unknown for us) goes to 0 and a 1GB KERNEL_IMAGE_SIZE is assumed. With that the biggest cSlots which can be 2493 * achieved is 64. The chosen random offset is taken from a random long integer using kaslr_get_random_long() modulo the 2494 * number of slots which selects a slot between 0 and 63. The final offset is calculated using: 2495 * offAddr = random_addr * 0x1000000 (CONFIG_PHYSICAL_ALIGN) + 0x1000000 (minimum) 2496 * 2497 * So the highest offset the kernel can start is 0x40000000 which is 1GB (plus the maximum kernel size we defined). 2498 */ 2499 if (dbgDiggerLinuxProbeWithAddr(pThis, pUVM, uAddrKernelStart, _1G + LNX_MAX_KERNEL_SIZE)) 2500 return true; 2501 2502 return false; 2503 } 2504 2505 /** 2414 2506 * @copydoc DBGFOSREG::pfnInit 2415 2507 */ … … 2462 2554 PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData; 2463 2555 2464 /*2465 * Look for "Linux version " at the start of the rodata segment.2466 * Hope that this comes before any message buffer or other similar string.2467 */2468 2556 for (unsigned i = 0; i < RT_ELEMENTS(g_au64LnxKernelAddresses); i++) 2469 2557 { 2470 DBGFADDRESS KernelAddr; 2471 DBGFR3AddrFromFlat(pUVM, &KernelAddr, g_au64LnxKernelAddresses[i]); 2472 DBGFADDRESS HitAddr; 2473 int rc = DBGFR3MemScan(pUVM, 0, &KernelAddr, LNX_MAX_KERNEL_SIZE, 1, 2474 g_abLinuxVersion, sizeof(g_abLinuxVersion) - 1, &HitAddr); 2475 if (RT_SUCCESS(rc)) 2476 { 2477 char szTmp[128]; 2478 char const *pszX = &szTmp[sizeof(g_abLinuxVersion) - 1]; 2479 rc = DBGFR3MemReadString(pUVM, 0, &HitAddr, szTmp, sizeof(szTmp)); 2480 if ( RT_SUCCESS(rc) 2481 && ( ( pszX[0] == '2' /* 2.x.y with x in {0..6} */ 2482 && pszX[1] == '.' 2483 && pszX[2] >= '0' 2484 && pszX[2] <= '6') 2485 || ( pszX[0] >= '3' /* 3.x, 4.x, ... 9.x */ 2486 && pszX[0] <= '9' 2487 && pszX[1] == '.' 2488 && pszX[2] >= '0' 2489 && pszX[2] <= '9') 2490 ) 2491 ) 2492 { 2493 pThis->AddrKernelBase = KernelAddr; 2494 pThis->AddrLinuxBanner = HitAddr; 2495 return true; 2496 } 2497 } 2498 } 2558 if (dbgDiggerLinuxProbeWithAddr(pThis, pUVM, g_au64LnxKernelAddresses[i], LNX_MAX_KERNEL_SIZE)) 2559 return true; 2560 } 2561 2562 /* Maybe the kernel uses KASLR. */ 2563 if (dbgDiggerLinuxProbeKaslr(pThis, pUVM, LNX32_KERNEL_ADDRESS_START)) 2564 return true; 2565 2566 if (dbgDiggerLinuxProbeKaslr(pThis, pUVM, LNX64_KERNEL_ADDRESS_START)) 2567 return true; 2568 2499 2569 return false; 2500 2570 }
Note:
See TracChangeset
for help on using the changeset viewer.

