VirtualBox

Changeset 81647 in vbox for trunk/src/VBox/Devices/EFI


Ignore:
Timestamp:
Nov 4, 2019 11:38:14 AM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
134405
Message:

EFI/Firmware/VBoxApfsJmpStartDxe: Implement fletcher64 checksum generation and checking + some fixes and cleanups

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxApfsJmpStartDxe/VBoxApfsJmpStartDxe.c

    r81604 r81647  
    4444#include <iprt/formats/apfs.h>
    4545
    46 #define APFS_EFI_JMP_START_EXTENTS_MAX 32
    47 
    4846/**
    4947 * Contains the full jump start context being worked on.
     
    5957    /** Controller handle. */
    6058    EFI_HANDLE   hController;
    61     /** Full jump start structure. */
    62     struct
    63     {
    64         APFSEFIJMPSTART Hdr;
    65         APFSPRANGE      aExtents[APFS_EFI_JMP_START_EXTENTS_MAX];
    66     } JmpStart;
     59    /** APFS UUID. */
     60    APFSUUID     Uuid;
    6761} APFSJMPSTARTCTX;
    6862typedef APFSJMPSTARTCTX *PAPFSJMPSTARTCTX;
    6963typedef const APFSJMPSTARTCTX *PCAPFSJMPSTARTCTX;
    7064
    71 #if 0
    7265static EFI_GUID g_ApfsDrvLoadedFromThisControllerGuid = { 0x01aaf8bc, 0x9c37, 0x4dc1,
    7366                                                          { 0xb1, 0x68, 0xe9, 0x67, 0xd4, 0x2c, 0x79, 0x25 } };
    74 #else
    75 static EFI_GUID g_ApfsDrvLoadedFromThisControllerGuid = { 0x03B8D751, 0xA02F, 0x4FF8,
    76                                                           { 0x9B, 0x1A, 0x55, 0x24, 0xAF, 0xA3, 0x94, 0x5F } };
    77 #endif
    7867
    7968typedef struct APFS_DRV_LOADED_INFO
     
    10998}
    11099
     100/**
     101 * Calculates the fletcher64 checksum of the given APFS block and returns TRUE if it matches the one given in the object header.
     102 *
     103 * @returns Flag indicating whether the checksum matched.
     104 * @param   pObjHdr         The object header containing the checksum to check against.
     105 * @param   pvStruct        Pointer to the struct to create the checksum of.
     106 * @param   cbStruct        Size of the struct in bytes.
     107 */
    111108static BOOLEAN vboxApfsObjPhysIsChksumValid(PCAPFSOBJPHYS pObjHdr, void *pvStruct, size_t cbStruct)
    112109{
    113     return TRUE; /** @todo Checksum */
    114 }
    115 
    116 static EFI_STATUS vboxApfsJmpStartLoadAndExecEfiDriver(IN PAPFSJMPSTARTCTX pCtx, IN PCAPFSNXSUPERBLOCK pSb)
    117 {
    118     UINTN cbReadLeft = RT_LE2H_U32(pCtx->JmpStart.Hdr.cbEfiFile);
     110    if (cbStruct % sizeof(uint32_t) == 0)
     111    {
     112        uint32_t *pu32Data = (uint32_t *)pvStruct + 2; /* Start after the checksum field at the beginning. */
     113        size_t cWordsLeft = (cbStruct >> 2) - 2;
     114
     115        uint64_t u64C0 = 0;
     116        uint64_t u64C1 = 0;
     117        uint64_t u64ChksumFletcher64 = 0;
     118        uint64_t u64Check0 = 0;
     119        uint64_t u64Check1 = 0;
     120
     121        while (cWordsLeft)
     122        {
     123            u64C0 += (uint64_t)*pu32Data++;
     124            u64C0 %= UINT32_C(0xffffffff);
     125
     126            u64C1 += u64C0;
     127            u64C1 %= UINT32_C(0xffffffff);
     128
     129            cWordsLeft--;
     130        }
     131
     132        u64Check0 = UINT32_C(0xffffffff) - (u64C0 + u64C1) % UINT32_C(0xffffffff);
     133        u64Check1 = UINT32_C(0xffffffff) - (u64C0 + u64Check0) % UINT32_C(0xffffffff);
     134
     135        u64ChksumFletcher64 = (uint64_t)u64Check1 << 32 | u64Check0;
     136        if (!CompareMem(&u64ChksumFletcher64, &pObjHdr->abChkSum[0], sizeof(pObjHdr->abChkSum)))
     137            return TRUE;
     138        else
     139            DEBUG((DEBUG_INFO, "vboxApfsObjPhysIsChksumValid: Checksum mismatch, expected 0x%llx got 0x%llx", u64ChksumFletcher64, *(uint64_t *)&pObjHdr->abChkSum[0]));
     140    }
     141    else
     142        DEBUG((DEBUG_INFO, "vboxApfsObjPhysIsChksumValid: Structure not a multiple of 32bit\n"));
     143
     144    return FALSE;
     145}
     146
     147/**
     148 * Loads and starts the EFI driver contained in the given jump start structure.
     149 *
     150 * @returns EFI status code.
     151 * @param   pCtx            APFS jump start driver context structure.
     152 * @param   pJmpStart       APFS jump start structure describing the EFI file to load and start.
     153 */
     154static EFI_STATUS vboxApfsJmpStartLoadAndExecEfiDriver(IN PAPFSJMPSTARTCTX pCtx, IN PCAPFSEFIJMPSTART pJmpStart)
     155{
     156    PCAPFSPRANGE paExtents = (PCAPFSPRANGE)(pJmpStart + 1);
     157    UINTN cbReadLeft = RT_LE2H_U32(pJmpStart->cbEfiFile);
    119158    EFI_STATUS rc = EFI_SUCCESS;
    120159
     
    125164        uint8_t *pbBuf = (uint8_t *)pvApfsDrv;
    126165
    127         for (i = 0; i < RT_LE2H_U32(pCtx->JmpStart.Hdr.cExtents) && !EFI_ERROR(rc) && cbReadLeft; i++)
     166        for (i = 0; i < RT_LE2H_U32(pJmpStart->cExtents) && !EFI_ERROR(rc) && cbReadLeft; i++)
    128167        {
    129             PCAPFSPRANGE pRange = &pCtx->JmpStart.aExtents[i];
    130             UINTN cbRead = RT_MIN(cbReadLeft, (UINTN)RT_LE2H_U64(pRange->cBlocks) * pCtx->cbBlock);
    131 
    132             rc = vboxApfsJmpStartRead(pCtx, RT_LE2H_U64(pRange->PAddrStart), pbBuf, cbRead);
     168            UINTN cbRead = RT_MIN(cbReadLeft, (UINTN)RT_LE2H_U64(paExtents[i].cBlocks) * pCtx->cbBlock);
     169
     170            rc = vboxApfsJmpStartRead(pCtx, RT_LE2H_U64(paExtents[i].PAddrStart), pbBuf, cbRead);
    133171            pbBuf      += cbRead;
    134172            cbReadLeft -= cbRead;
     
    147185
    148186                rc = gBS->LoadImage(FALSE, gImageHandle, ParentDevicePath,
    149                                     pvApfsDrv, RT_LE2H_U32(pCtx->JmpStart.Hdr.cbEfiFile),
     187                                    pvApfsDrv, RT_LE2H_U32(pJmpStart->cbEfiFile),
    150188                                    &hImage);
    151189                if (!EFI_ERROR(rc))
     
    159197                        {
    160198                            pApfsDrvLoadedInfo->hController = pCtx->hController;
    161                             CopyMem(&pApfsDrvLoadedInfo->GuidContainer, &pSb->Uuid, sizeof(pApfsDrvLoadedInfo->GuidContainer));
     199                            CopyMem(&pApfsDrvLoadedInfo->GuidContainer, &pCtx->Uuid, sizeof(pApfsDrvLoadedInfo->GuidContainer));
    162200
    163201                            rc = gBS->InstallMultipleProtocolInterfaces(&pCtx->hController, &g_ApfsDrvLoadedFromThisControllerGuid, pApfsDrvLoadedInfo, NULL);
     
    165203                            {
    166204                                /* Connect the driver with the controller it came from. */
    167 #if 0
    168205                                EFI_HANDLE ahImage[2];
    169206
    170207                                ahImage[0] = hImage;
    171208                                ahImage[1] = NULL;
    172 #endif
    173                                 gBS->ConnectController(pCtx->hController, NULL /*&ahImage[0]*/, NULL, TRUE);
     209
     210                                gBS->ConnectController(pCtx->hController, &ahImage[0], NULL, TRUE);
    174211                                return EFI_SUCCESS;
    175212                            }
     
    284321            rc = vboxApfsJmpStartRead(&Ctx, 0, &Sb, sizeof(Sb));
    285322            if (   !EFI_ERROR(rc)
    286                 && RT_LE2H_U32(Sb.u32Magic) == APFS_NX_SUPERBLOCK_MAGIC
    287                 && RT_LE2H_U64(Sb.PAddrEfiJmpStart) > 0
    288                 && vboxApfsObjPhysIsChksumValid(&Sb.ObjHdr, &Sb, sizeof(Sb)))
     323                && RT_LE2H_U32(Sb.u32Magic) == APFS_NX_SUPERBLOCK_MAGIC)
    289324            {
    290                 Ctx.cbBlock = RT_LE2H_U32(Sb.cbBlock);
    291 
    292                 DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Found APFS superblock, reading jumpstart structure from %llx\n", RT_LE2H_U64(Sb.PAddrEfiJmpStart)));
    293                 rc = vboxApfsJmpStartRead(&Ctx, RT_LE2H_U64(Sb.PAddrEfiJmpStart), &Ctx.JmpStart, sizeof(Ctx.JmpStart));
    294                 if (   !EFI_ERROR(rc)
    295                     && RT_H2LE_U32(Ctx.JmpStart.Hdr.u32Magic) == APFS_EFIJMPSTART_MAGIC
    296                     && RT_H2LE_U32(Ctx.JmpStart.Hdr.u32Version) == APFS_EFIJMPSTART_VERSION
    297                     && vboxApfsObjPhysIsChksumValid(&Ctx.JmpStart.Hdr.ObjHdr, &Ctx.JmpStart.Hdr, sizeof(Ctx.JmpStart.Hdr))
    298                     && RT_H2LE_U32(Ctx.JmpStart.Hdr.cExtents) <= APFS_EFI_JMP_START_EXTENTS_MAX)
    299                     rc = vboxApfsJmpStartLoadAndExecEfiDriver(&Ctx, &Sb);
     325                uint8_t *pbBlock = (uint8_t *)AllocateZeroPool(RT_LE2H_U32(Sb.cbBlock));
     326
     327                if (pbBlock)
     328                {
     329                    PCAPFSNXSUPERBLOCK pSb = (PCAPFSNXSUPERBLOCK)pbBlock;
     330
     331                    /* Read in the complete block (checksums always cover the whole block and not just the structure...). */
     332                    Ctx.cbBlock = RT_LE2H_U32(Sb.cbBlock);
     333
     334                    rc = vboxApfsJmpStartRead(&Ctx, 0, pbBlock, Ctx.cbBlock);
     335                    if (   !EFI_ERROR(rc)
     336                        && RT_LE2H_U64(Sb.PAddrEfiJmpStart) > 0
     337                        && vboxApfsObjPhysIsChksumValid(&pSb->ObjHdr, pbBlock, Ctx.cbBlock))
     338                    {
     339                        PCAPFSEFIJMPSTART pJmpStart = (PCAPFSEFIJMPSTART)pbBlock;
     340
     341                        DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Found APFS superblock, reading jumpstart structure from %llx\n", RT_LE2H_U64(Sb.PAddrEfiJmpStart)));
     342
     343                        CopyMem(&Ctx.Uuid, &pSb->Uuid, sizeof(Ctx.Uuid));
     344
     345                        rc = vboxApfsJmpStartRead(&Ctx, RT_LE2H_U64(Sb.PAddrEfiJmpStart), pbBlock, Ctx.cbBlock);
     346                        if (   !EFI_ERROR(rc)
     347                            && RT_H2LE_U32(pJmpStart->u32Magic) == APFS_EFIJMPSTART_MAGIC
     348                            && RT_H2LE_U32(pJmpStart->u32Version) == APFS_EFIJMPSTART_VERSION
     349                            && vboxApfsObjPhysIsChksumValid(&pJmpStart->ObjHdr, pbBlock, Ctx.cbBlock)
     350                            && RT_H2LE_U32(pJmpStart->cExtents) <= (Ctx.cbBlock - sizeof(*pJmpStart)) / sizeof(APFSPRANGE))
     351                            rc = vboxApfsJmpStartLoadAndExecEfiDriver(&Ctx, pJmpStart);
     352                        else
     353                        {
     354                            rc = EFI_UNSUPPORTED;
     355                            DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: The APFS EFI jumpstart structure is invalid\n"));
     356                        }
     357                    }
     358                    else
     359                    {
     360                        DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Invalid APFS superblock -> no APFS filesystem (%r %x %llx)\n", rc, Sb.u32Magic, Sb.PAddrEfiJmpStart));
     361                        rc = EFI_UNSUPPORTED;
     362                    }
     363
     364                    FreePool(pbBlock);
     365                }
    300366                else
    301                 {
    302                     rc = EFI_UNSUPPORTED;
    303                     DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: The APFS EFI jumpstart structure is invalid\n"));
    304                 }
     367                    DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Failed to allocate memory for APFS block data (%u bytes)\n", RT_LE2H_U32(Sb.cbBlock)));
    305368            }
    306369            else
    307             {
    308                 DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Invalid APFS superblock -> no APFS filesystem (%r %x %llx)\n", rc, Sb.u32Magic, Sb.PAddrEfiJmpStart));
    309                 rc = EFI_UNSUPPORTED;
    310             }
     370                DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Invalid APFS superblock -> no APFS filesystem (%r %x)\n", rc, Sb.u32Magic));
    311371
    312372            gBS->CloseProtocol(ControllerHandle,
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette