acidanthera / bugtracker

Acidanthera Bugtracker
385 stars 45 forks source link

OpenCore EFI partition that are read-only are currently not supported #1242

Closed Thireus closed 4 years ago

Thireus commented 4 years ago

Currently OpenCore requires write access to the EFI partition in order to function. Several files are written to that partition (not only log files) when OpenCore loads. If write access isn't provided, OpenCore will not load and will display:

OC: Driver HfsPlus.efi at 0 cannot be found! Halting on critical error

Any chance to support read-only EFI partitions in the future?

Some users might find it helpful to support read-only bootloaders which helps prevent bootloader tampering.

vit9696 commented 4 years ago

This is not right. Read-only partitions are supported, OpenCore will boot fine when it cannot create a log file silently avoiding log file creation. The error you pasted says that you have a mistake on your configuration caused by the HfsPlus.efi driver file not present on the filesystem.

Thireus commented 4 years ago

Hi vit9696,

First of all, I just wanted to say thank you, I really appreciate your hard work.

Now, I can understand why your immediate reaction was to reject the issue when you saw it related to HfsPlus.efi missing, which appears to be a common mistake made by many novice users.

Rest assured that I have checked my configuration more than once.

My HfsPlus.efi file is present on my OpenCore EFI and is located there: /Volumes/EFI/EFI/OC/Drivers/HfsPlus.efi

I can also confirm that my OpenCore EFI works very well when my drive is set to RW. I can confirm I am able to boot on macOS just fine. The issue only occurs when I set the SAME drive in RO mode.

The drive is an SD card which can easily be set to RO by a flip of the side switch. So this is the same setup, the same files, the same drive.

I also understand it is certainly not related to log files. I was just pointing out that in RW mode, there are files written by OpenCore and logs are some of them.

Please advise. Thank you.


Steps to reproduce the issue:

  1. Install OpenCore on an SD Card
  2. Configure OpenCore and verify it works just fine. yay
  3. Flip the SD Card switch to RO and attempt to boot
  4. OpenCore complains about HfsPlus.efi... :(
1alessandro1 commented 4 years ago

@Thireus I'm using a Kanguru FlashBlu 16GB usb drive which has a "true" read only switch once you've made the USB which is not host dependant as the card switch.

No issues so far in read-only and RW mode, with macOS, Linux, windows etc.

You should know that the operating system itself accepts to mount the SD card read-only, and this could be exploited easily since it's only a software limitation not a hardware switch which limits the maximum current/voltage to the flash storage for writing, since the necessary voltage required for writing is greater than the one requested for reading

vit9696 commented 4 years ago

This would be file system corruption or BIOS driver issues in this case. I.e. the file system on your SD card for some reason is not valid for the file system driver in your BIOS, and thus OpenCore does not see anything. I am afraid not much can be done about it, since it is an issue with the particular hardware on the BIOS side, but you could try reformatting your SD card.

1alessandro1 commented 4 years ago

You could try to use a USB card reader but that would instantly bypass the read-only card's switch making it RW

Thireus commented 4 years ago

Thank you both for the tips. @vit9696 I think you just guessed it right, there is something going on with the BIOS and SD card FS.

I've just tired to boot OpenCore using VirtualBox. It works! Even with RO enabled on the SD card... So, nothing wrong with OpenCore then. I'll continue investigating the issue and post an update here once I found the culprit.

Thireus commented 4 years ago

Update:

The following code is executed (cf. https://github.com/acidanthera/OpenCorePkg/blob/master/Library/OcStorageLib/OcStorageLib.c#L247):

  Status = SafeFileOpen (
    Context->StorageRoot,
    &File,
    (CHAR16 *) FilePath,
    EFI_FILE_MODE_READ,
    0
    );

The Status value is "8" when attempting to access Drivers/HfsPlus.efi when I boot the SD Card as Read Only.

That seems to corresponds to the following (cf https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiBaseType.h):

define EFI_WRITE_PROTECTED RETURN_WRITE_PROTECTED

This is what I've modified in the code:

  if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_WARN, "THIREUS: EFI_ERROR %s: %d\n", FilePath, Status));
    return NULL;
  }

This is what OpenCore displays:

THIREUS: EFI_ERROR Drivers\HfsPlus.efi: 8

This seems very strange that RETURN_WRITE_PROTECTED is considered as an error, especially when EFI_FILE_MODE_READ is specified... Any idea why?

I'll patch the code to accept Status 8 as a non-EFI_ERROR and see how it goes.

Thireus commented 4 years ago

This is a patch that works for my RO SD Card:

    // Thireus patch
    if (OpenMode == EFI_FILE_MODE_READ && Status == EFI_WRITE_PROTECTED){
        Status = EFI_SUCCESS;
    }

Patched inside https://github.com/acidanthera/OpenCorePkg/blob/master/Library/OcFileLib/OpenFile.c Functions: SafeFileOpen(...) and OcOpenFileByDevicePath(...) before the return Status;.

I can confirm I can finally boot successfully in RO mode with the above.

I'm not knowledgeable on EFI functioning. To me it seems that whichever lib is handling EFI Open operations it is not correctly interpreting the EFI_FILE_MODE_READ Openmode and triggers by mistake a RETURN_WRITE_PROTECTED EFI_ERROR when the accessed resource is read-only...

Is my BIOS manufacturer to blame? @vit9696, any idea?

vit9696 commented 4 years ago

According to the UEFI specification, page 510, EFI_WRITE_PROTECTED can only be returned from EFI_FILE_PROTOCOL Open function when An attempt was made to create a file, or open a file for write when the media is write-protected.. This an error condition and the file does not open in this case as the only condition for file open is EFI_SUCCESSThe file was opened. So yes, your BIOS is not behaving correctly and is violating the specification.

On the other side I do not believe it is possible for a valid firmware to return EFI_WRITE_PROTECTED for EFI_FILE_MODE_READ, so we could technically add a hack for your BIOS to treat file reads resulting in write protected as successful operations without affecting other systems.

If others do not mind, I suggest to change the code as shown below. OcOpenFileByDevicePath does not need to be changed as it eventually uses SafeFileOpen as well. This code snippet will need testing before merging AND it will need the comments clarifying what exact board, firmware (if known), CPU generation, SD card, and card reader this was reproduced on.

EFI_STATUS
SafeFileOpen (
  IN  EFI_FILE_PROTOCOL       *Protocol,
  OUT EFI_FILE_PROTOCOL       **NewHandle,
  IN  CONST CHAR16            *FileName,
  IN  UINT64                  OpenMode,
  IN  UINT64                  Attributes
  )
{
  EFI_STATUS  Status;
  UINTN       Length;

  DEBUG_CODE_BEGIN ();
  ASSERT (FileName != NULL);
  ASSERT (NewHandle != NULL);
  Length = StrLen (FileName);
  if (Length > 0 && FileName[Length - 1] == L'\\') {
    DEBUG ((DEBUG_INFO, "OCFS: Filename %s has trailing slash\n", FileName));
  }
  DEBUG_CODE_END ();

  *NewHandle = NULL;
  Status = Protocol->Open (
    Protocol,
    NewHandle,
    (CHAR16 *) FileName,
    OpenMode,
    Attributes
    );

  if (Status == EFI_WRITE_PROTECTED
    && OpenMode == EFI_FILE_MODE_READ
    && Attributes == 0
    && *NewHandle != NULL) {
    Status = EFI_SUCCESS;
  }

  return Status;
}

CC @Download-Fritz @Goldfish64

mhaeuser commented 4 years ago

@vit9696 Maybe add a DEBUG_INFO so that if we ever run into a weird issue with this it's at least visible?

vit9696 commented 4 years ago

Won't risk the recursion; verbose at most.

Thireus commented 4 years ago

Hi @vit9696, thank you for the explanation. I'll write to Asus and see if they can fix that in their next x299 BIOS release.

Unfortunately only patching SafeFileOpen is not sufficient (I've tried). When Kext plists are loaded (ie. Lilu.kext) the OcOpenFileByDevicePath function is used instead. So that one also requires patching.

SafeFileOpen:

EFI_STATUS
SafeFileOpen (
  IN  EFI_FILE_PROTOCOL       *Protocol,
  OUT EFI_FILE_PROTOCOL       **NewHandle,
  IN  CONST CHAR16            *FileName,
  IN  UINT64                  OpenMode,
  IN  UINT64                  Attributes
  )
{
  EFI_STATUS  Status;
  UINTN       Length;

  DEBUG_CODE_BEGIN ();
  ASSERT (FileName != NULL);
  Length = StrLen (FileName);
  if (Length > 0 && FileName[Length - 1] == L'\\') {
    DEBUG ((DEBUG_INFO, "OCFS: Filename %s has trailing slash\n", FileName));
  }
  DEBUG_CODE_END ();

  Status = Protocol->Open (
    Protocol,
    NewHandle,
    (CHAR16 *) FileName,
    OpenMode,
    Attributes
    );

  if (Status == EFI_WRITE_PROTECTED
    && OpenMode == EFI_FILE_MODE_READ
    && Attributes == 0
    && *NewHandle != NULL) {
    Status = EFI_SUCCESS;
  }

  return Status;
}

OcOpenFileByDevicePath:

EFI_STATUS
EFIAPI
OcOpenFileByDevicePath (
  IN OUT EFI_DEVICE_PATH_PROTOCOL  **FilePath,
  OUT    EFI_FILE_PROTOCOL         **File,
  IN     UINT64                    OpenMode,
  IN     UINT64                    Attributes
  )
{
  EFI_STATUS Status;
  EFI_HANDLE FileSystemHandle;

  ASSERT (File != NULL);
  ASSERT (FilePath != NULL);

  //
  // Look up the filesystem.
  //
  Status = gBS->LocateDevicePath (
                  &gEfiSimpleFileSystemProtocolGuid,
                  FilePath,
                  &FileSystemHandle
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = OcOpenFileByRemainingDevicePath (
             FileSystemHandle,
             *FilePath,
             File,
             OpenMode,
             Attributes
             );

  if (Status == EFI_WRITE_PROTECTED
    && OpenMode == EFI_FILE_MODE_READ
    && Attributes == 0
    && *File != NULL) {
    Status = EFI_SUCCESS;
  }

  return Status;
}

Recompiling OpenCore and all Kexts is necessary.

I can confirm that patching both SafeFileOpen and OcOpenFileByDevicePath is a requirement and works with the latest OpenCore commit: ba5eea2de4c347630441df71f933a01f8e9198fb.

vit9696 commented 4 years ago

But OcOpenFileByRemainingDevicePath calls SafeFileOpen, its implementation is right above. So it must be some other inner call that fails. Could you trace it? It is not correct to fix OcOpenFileByDevicePath, should be somewhere in its children.

Also, please be more descriptive about your board.

vit9696 commented 4 years ago

I believe it is OpenVolume (https://github.com/acidanthera/OpenCorePkg/blob/master/Library/OcFileLib/OpenFile.c#L99) that causes issues. Could you check it? If so, we should introduce SafeOpenVolume and fix it in more places.

Thireus commented 4 years ago

@vit9696, could be OpenVolume indeed. I will try trace it as soon as I have some free time and I'll let you know exactly where it gets the EFI_WRITE_PROTECTED Status from.

BIOS: ROG RAMPAGE VI EXTREME BIOS 3105 BOARD: ROG RAMPAGE VI EXTREME LINK: https://rog.asus.com/us/motherboards/rog-rampage/rog-rampage-vi-extreme-model/helpdesk_bios/

Thireus commented 4 years ago

@vit9696, my mistake. I can confirm only patching SafeFileOpen is sufficient!

Most likely I had not recompiled the kexts properly during my previous tests.

Also, I just opened a ticket with Asus. Hopefully they'll be able to acknowledge that they don't follow the specs and patch that in the next BIOS release.

sampath-houde commented 3 years ago

Bro, I am using acer swift3 sf314-55g laptop. I am getting error Driver HfsPlus.efi at 0 cannot be found!. I will attach my config.plist to it. sampath config.zip