From: srs5694 Date: Thu, 5 Nov 2015 02:11:36 +0000 (-0500) Subject: Further refinements to SIP/CSR/rootless support, including X-Git-Url: https://code.delx.au/refind/commitdiff_plain/7f97f502da6c482383f038970e788e1d005d391b Further refinements to SIP/CSR/rootless support, including documentation. --- diff --git a/docs/refind/about.png b/docs/refind/about.png new file mode 100644 index 0000000..e28fc11 Binary files /dev/null and b/docs/refind/about.png differ diff --git a/docs/refind/configfile.html b/docs/refind/configfile.html index 5e8fc00..c62fcd5 100644 --- a/docs/refind/configfile.html +++ b/docs/refind/configfile.html @@ -292,8 +292,8 @@ timeout 20 showtools - shell, memtest, gdisk, gptsync, apple_recovery, mok_tool, netboot, about, exit, shutdown, reboot, and firmware - Specifies which tool tags to display on the second row. shell launches an EFI shell, memtest (or memtest86) launches the Memtest86 program, gdisk launches the partitioning tool of the same name, gptsync launches a tool that creates a hybrid MBR, apple_recovery boots the OS X Recovery HD, windows_recovery boots a Windows recovery tool, mok_tool launches a tool to manage Machine Owner Keys (MOKs) on systems with Secure Boot active, netboot launches the network boot tool (iPXE), about displays information about rEFInd, exit terminates rEFInd, shutdown shuts down the computer (or reboots it, on some UEFI PCs), reboot reboots the computer, and firmware reboots the computer into the computer's own setup utility. The tags appear in the order in which you specify them. The default is shell, memtest, gdisk, apple_recovery, mok_tool, about, shutdown, reboot, firmware. Note that the shell, memtest, apple_recovery, and mok_tool options all require the presence of programs not included with rEFInd. The gptsync option requires use of a like-named program which, although it ships with rEFInd 0.6.9 and later, is not installed by default except under OS X. See the "Installing Additional Components" section of the Installing rEFInd page for pointers to the shell, Memtest86, and gptsync programs. The apple_recovery option will appear only if you've got an Apple Recovery HD partition (which has a boot loader called com.apple.recovery.boot/boot.efi). The firmware option works only on computers that support this option; on other computers, the option is quietly ignored. See the Secure Boot page for information on Secure Boot and MOK management. + shell, memtest, gdisk, gptsync, apple_recovery, csr_rotate, mok_tool, netboot, about, exit, shutdown, reboot, and firmware + Specifies which tool tags to display on the second row. shell launches an EFI shell, memtest (or memtest86) launches the Memtest86 program, gdisk launches the partitioning tool of the same name, gptsync launches a tool that creates a hybrid MBR, apple_recovery boots the OS X Recovery HD, csr_rotate rotates through System Integrity Protection (SIP) values specified by csr_values, windows_recovery boots a Windows recovery tool, mok_tool launches a tool to manage Machine Owner Keys (MOKs) on systems with Secure Boot active, netboot launches the network boot tool (iPXE), about displays information about rEFInd, exit terminates rEFInd, shutdown shuts down the computer (or reboots it, on some UEFI PCs), reboot reboots the computer, and firmware reboots the computer into the computer's own setup utility. The tags appear in the order in which you specify them. The default is shell, memtest, gdisk, apple_recovery, mok_tool, about, shutdown, reboot, firmware. Note that the shell, memtest, apple_recovery, and mok_tool options all require the presence of programs not included with rEFInd. The gptsync option requires use of a like-named program which, although it ships with rEFInd 0.6.9 and later, is not installed by default except under OS X. See the "Installing Additional Components" section of the Installing rEFInd page for pointers to the shell, Memtest86, and gptsync programs. The apple_recovery option will appear only if you've got an Apple Recovery HD partition (which has a boot loader called com.apple.recovery.boot/boot.efi). The firmware option works only on computers that support this option; on other computers, the option is quietly ignored. See the Secure Boot page for information on Secure Boot and MOK management. font @@ -395,6 +395,11 @@ timeout 20 string (10.9 suggested) On some Macs, this option causes rEFInd to tell the firmware that the specified version of OS X is being launched, even when another OS is selected. The effect is that the firmware may initialize hardware differently, which may have beneficial (or detrimental) results. If your Mac's video output isn't working normally, this option may help. On the other hand, keyboards and mice are known to sometimes stop functioning if this option is used, so you shouldn't use it unnecessarily. This option has no effect on non-Apple hardware. The default is to not use this feature. + + csr_rotate + List of hexadecimal values + Specifies values that may be set via the csr_rotate tool for Apple's System Integrity Protection (SIP). SIP stores values in NVRAM to set restrictions on what users (even root) may do in recent versions of OS X. If you want to be able to control these restrictions in rEFInd, you must set the values you want to use here and set csr_rotate on the showtools line (which must also be uncommented). Note that values are specified in hexadecimal, with no leading 0x or other hexadecimal indicator. SIP is described in more detail on many Web sites, such as here and here. + include filename diff --git a/docs/refind/func_csr_rotate.png b/docs/refind/func_csr_rotate.png new file mode 100644 index 0000000..75fa419 Binary files /dev/null and b/docs/refind/func_csr_rotate.png differ diff --git a/docs/refind/recovery-mode.png b/docs/refind/recovery-mode.png deleted file mode 100644 index 8e6a54e..0000000 Binary files a/docs/refind/recovery-mode.png and /dev/null differ diff --git a/docs/refind/sip.html b/docs/refind/sip.html index fa589b7..905e4a0 100644 --- a/docs/refind/sip.html +++ b/docs/refind/sip.html @@ -129,17 +129,61 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com


-

Apple's OS X 10.11 (aka El Capitan) includes a new feature, known as System Integrity Protection (SIP), aka "rootless" mode. To understand SIP, you should first know that Unix-like systems, including OS X, have traditionally provided a model of security in which ordinary users can read and write their own files (word processor documents, their own digital photos, etc.), but not system files (programs, system configuration files, etc.). This system security model has worked well for decades on traditional Unix systems, which have been administered by computer professionals and used by individuals with less experience. For administrative tasks, the root account is used; on Macs, this access is generally granted by the sudo command or by various GUI tools. Most Macs are single-user computers that are administered by their users. Such people often lack the knowledge of the professional system administrators who have traditionally managed Unix systems; but they must still perform system administration tasks such as installing new software and configuring network settings. OS X has always provided some measure of security by requiring users to enter their passwords before performing these dangerous tasks, and by providing GUI tools to help guide users through these tasks in a way that minimizes the risk of damage.

+
+ +

Apple's OS X 10.11 (aka El Capitan) includes a new feature, known as System Integrity Protection (SIP), aka "rootless" mode. This feature is causing some consternation for advanced users, because it restricts what you can do with your computer, even as root. This page is dedicated to this new feature, including basic information on why SIP exists, how to install rEFInd on a computer with SIP enabled, and how to use rEFInd to manage SIP.

+ +
+ + + + +

What Is SIP?

+
+ +

To understand SIP, you should first know that Unix-like systems, including OS X, have traditionally provided a model of security in which ordinary users can read and write their own files (word processor documents, their own digital photos, etc.), but cannot write to system files (programs, system configuration files, etc.)—and users cannot even read some system files. This system security model has worked well for decades on traditional Unix systems, which have been administered by computer professionals and used by individuals with less experience. For administrative tasks, the root account is used. On Macs, this access is generally granted by the sudo command or by various GUI tools. Most Macs are single-user computers that are administered by their users. Such people often lack the knowledge of the professional system administrators who have traditionally managed Unix systems; but they must still perform system administration tasks such as installing new software and configuring network settings. OS X has always provided some measure of security by requiring users to enter their passwords before performing these dangerous tasks, and by providing GUI tools to help guide users through these tasks in a way that minimizes the risk of damage.

Apple has apparently decided that these safeguards are no longer sufficient. I won't try to speak for Apple or explain their motivations, but the result of Apple's decisions is SIP. With SIP active, as is the default, OS X limits your ability to perform some of these administrative tasks. You can still install and remove most third-party programs, configure your network, and so on; but some critical directories can no longer be written, even as root, and some utilities cannot be used in certain ways, even as root. These restrictions impact rEFInd because one of the affected tools, a command called bless, is required to tell the Mac to boot rEFInd rather than to boot OS X directly.

-

The end result of SIP is that rEFInd cannot be installed under OS X 10.11 in the way described on the Installing rEFInd page—at least, not without first booting into Recovery mode, in which SIP restrictions are ignored or disabling SIP. This page covers these two options in more detail, as well as a third: Using another OS to install rEFInd.

+ +

Installing rEFInd with SIP Enabled

+
+ +

The end result of SIP is that rEFInd cannot be installed under OS X 10.11 in the way described on the Installing rEFInd page—at least, not without first booting into Recovery mode, in which SIP restrictions are ignored; or disabling SIP (either temporarily or permanently). This page covers these two options in more detail, as well as a third: Using another OS to install rEFInd.

-

Using Recovery Mode

+

Using Recovery Mode

-

Unless you've deleted its partition, the Recovery HD partition should be present on your Mac as a way to perform emergency recovery operations. The nature of this tool means that SIP cannot be enabled, so you can install rEFInd from a boot to this partition. The trouble is that this installation is not a full-fledged OS X system, so you may have trouble using it if you're not comfortable with such a bare-bones environment. Nontheless, it is arguably the best way to install rEFInd on a Mac that runs OS X 10.11. To do so, follow these steps:

+

Unless you've deleted it, the Recovery HD partition should be present on your Mac as a way to perform emergency recovery operations. The nature of this tool means that SIP cannot be enabled when using it, so you can install rEFInd from a boot to this partition. The trouble is that this installation is not a full-fledged OS X system, so you may have trouble using it if you're not comfortable with such a bare-bones environment. Nontheless, it is arguably the best way to install rEFInd on a Mac that runs OS X 10.11. To do so, follow these steps:

    @@ -147,11 +191,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

  1. Reboot the computer.
  2. -
  3. At the startup chime, hold down the Option+R key combination. The computer should launch into the Recovery system. This is a very bare system, with only a window providing a way to launch a handful of utilities and a menu bar, as shown here:
  4. - -
    To install rEFInd, you must launch the Terminal from
-    the menu bar.

    +
  5. At the startup chime, hold down the Option+R key combination. The computer should launch into the Recovery system. This is a very bare system, with only a window providing a way to launch a handful of utilities and a menu bar. You must use the latter.
  6. Select Utilities -> Terminal from the menu bar. A Terminal window should open.
  7. @@ -159,13 +199,13 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

  8. Increase the size of the Terminal a bit. (This just makes its output more legible, since the next step produces long lines.)
  9. -
  10. Type df -h in the Terminal. This produces a list of partitions that are mounted. Locate the one on which you unpacked the rEFInd files. It will normally be /Volumes/Somename, where Somename" is the volume's name.
  11. +
  12. Type df -h in the Terminal. This produces a list of partitions that are mounted. Locate the one on which you unpacked the rEFInd files. It will normally be /Volumes/Somename, where Somename is the volume's name.
  13. -
  14. In the Terminal, use cd to change to the directory where the rEFInd files you unpacked earlier are stored. For instance, on my MacBook, I would type cd /Volumes/Macintosh\ HD/Users/rodsmith/Destkop/refind-0.9.3. Note that if any element of this path includes a space, you must either enclose the entire path in quotes or precede the space with a backslash (\), as in this example's Macintish\ HD volume name.
  15. +
  16. In the Terminal, use cd to change to the directory where the rEFInd files you unpacked earlier are stored. For instance, on my MacBook, I would type cd /Volumes/Macintosh\ HD/Users/rodsmith/Destkop/refind-0.10.1. Note that if any element of this path includes a space, you must either enclose the entire path in quotes or precede the space with a backslash (\), as in this example's Macintish\ HD volume name.
  17. Type ls to verify that refind-install is present in this directory.
  18. -
  19. Type ./refind-install to run the installation script.
  20. It should run normally, as described on the Installing rEFInd page. You can add options, if you like, as described on the Installing rEFInd page. Alternatively, you can perform a manual installation, also as described on that page. +
  21. Type ./refind-install to run the installation script. It should run normally, as described on the Installing rEFInd page. You can add options, if you like, as described on that page. Alternatively, you can perform a manual installation, also as described on that page.
  22. Reboot.
  23. @@ -174,7 +214,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

    At this point, rEFInd should come up and enable you to boot into OS X and any other OS(es) that are already installed. You should not need to perform these steps again unless OS X re-installs its own boot loader or a subsequent OS installation overrides the default boot option. You can install an updated rEFInd and it should install correctly, provided you're installing it to the EFI System Partition (ESP). The refind-install script may complain about a failure, but because you're overwriting one rEFInd binary with another one, it should continue to boot.

    -

    Disabling SIP

    +

    Disabling SIP

    Another option is to disable SIP for your regular boot. This is a viable option if you're an expert who needs regular access to tools with which SIP interferes, such as low-level disk utilities. Regular users should probably avoid this option unless the preceding procedure does not work—and in that case, you should disable SIP temporarily and then re-enable it when you've finished installing rEFInd.

    @@ -190,7 +230,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

    If you want to re-enable SIP, you can do so in exactly the way you disabled it, except that you should type csrutil enable rather than csrutil disable in the Recovery environment.

    -

    Using Another OS

    +

    Using Another OS

    A final option for installing rEFInd on a Mac that runs with SIP enabled is to do the installation using another OS. This other OS could be an OS that's already installed or an emergency boot disk, such as an Ubuntu installation/recovery system.

    @@ -209,15 +249,50 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

    I've tested this method of installing rEFInd on my MacBook Air, but I can't promise it will work on all Macs—or even on an identical Mac with a configuration that's different from mine. My preference is to install rEFInd under OS X on Macs, because Apple likes to do things differently from everybody else, and so a Mac's firmware might not react in the usual way to tools like efibootmgr in Linux or bcdedit in Windows.

    - -

    Conclusion

    +
    +

    Using rEFInd to Manage SIP

    -

    Although the goal of increased security is a good one, SIP is causing problems for intermediate and advanced users. The good news is that the process to install rEFInd on a system that runs OS X 10.11, although more complex than it used to be, is not an impossible one. Furthermore, once you've done it, you shouldn't have to do it again for a while. (An update to OS X's boot loader is entirely possible, though. If nothing else, the next major OS X update may require re-installing rEFInd.)

    +

    Once rEFInd is installed, you can use it to manage SIP features; however, the rEFInd features needed to do this are disabled by default. You must uncomment or add two lines to your refind.conf file:

    + + + + + +

    Note that both of these options must be set appropriately. If either of them is missing or misconfigured, rEFInd will not display the new SIP tool. A typical configuration using these features might look like this:

    -

    +
    showtools shell,memtest,gdisk,csr_rotate,apple_recovery,windows_recovery,mok_tool,about,shutdown,reboot,firmware
    +csr_values 10,77
    + + The SIP rotation tool rotates through all the CSR values you set + +

    Once these options are set and you reboot into rEFInd, you should see a new shield icon, as shown at the right. When you select this tool, rEFInd identifies the next available CSR value from the list you specified and switches to that mode, rotating back to the start of the list once the end is reached. To confirm that the SIP mode has changed, rEFInd displays, for three seconds, a message identifying the new mode.

    + +

    Whether or not you've enabled these SIP features in refind.conf, rEFInd displays the current SIP status on its "About" page:

    + +
    rEFInd presents a graphical menu for selecting your
+    boot OS.

    + +

    Note the line that reads "System Integrity Protection is disabled (0x77)." This line will be updated whenever you use the CSR rotation tool, so if you've specified a large number of values and have forgotten where you are in your rotation, you can use the About screen to figure it out.

    + +

    Both the summary on the About page and the CSR rotation tool depend on the presence of the csr-active-config NVRAM variable, which is where this information is stored. Thus, these features will not be present on older Macs that have not seen the presence of an OS X version that sets this variable. Likewise, you probably won't see the SIP summary in About or be able to set these values via csr_rotate and csr_values on a UEFI-based PC. (You could always create the variable on such a system in some other way, in which case rEFInd would let you adjust it, but it would have no effect on any OS except OS X.)

    + +

    I provide these features in rEFInd as a convenience for developers and other advanced users who have a legitimate need to adjust their SIP settings. Using rEFInd for this purpose is much faster than booting into the OS X Recovery system to make these adjustments. I discourage others from playing with these settings, since changing them inappropriately could cause problems; that's why they're not enabled by default.

    + + +

    Conclusion

    +
    -

    +

    Although the goal of increased security is a good one, SIP is causing problems for intermediate and advanced users. The good news is that the process to install rEFInd on a system that runs OS X 10.11, although more complex than it used to be, is not an impossible one. Furthermore, once you've done it, you shouldn't have to do it again for a while. (An update to OS X's boot loader is entirely possible, though. If nothing else, the next major OS X update may require re-installing rEFInd.) For advanced users, rEFInd can adjust SIP settings, which can be helpful if you occasionally want to do something that require greater-than-typical privileges.


    diff --git a/docs/refind/using.html b/docs/refind/using.html index 8a79513..4d5f3e7 100644 --- a/docs/refind/using.html +++ b/docs/refind/using.html @@ -350,7 +350,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

    The scanfor option, described on the Configuring the Boot Manager page, controls rEFInd's detection of legacy OSes. On Macs, the default is to scan for such OSes, since a common boot scenario on Macs is dual-booting OS X and Windows, and of course BIOS support is required for this. On UEFI PCs, rEFInd defaults to not scanning for legacy OSes; thus, you must edit the scanfor item in the configuration file if you want to boot a legacy OS on a UEFI PC.

    - The legacy OS icon is identical for all OSes on UEFI-based PCs. diff --git a/refind.spec b/refind.spec index 267e2be..7744be5 100644 --- a/refind.spec +++ b/refind.spec @@ -1,6 +1,6 @@ Summary: EFI boot manager software Name: refind -Version: 0.9.2.4 +Version: 0.9.2.7 Release: 1%{?dist} Summary: EFI boot manager software License: GPLv3 diff --git a/refind/apple.c b/refind/apple.c index d9ce975..bc72cbb 100644 --- a/refind/apple.c +++ b/refind/apple.c @@ -29,44 +29,42 @@ CHAR16 *gCsrStatus = NULL; // Get CSR (Apple's System Integrity Protection [SIP], or "rootless") status -// byte. Return values: -// -2 = Call succeeded but returned value of unexpected length, so result -// is suspect -// -1 = Call failed; likely not an Apple, or an Apple running OS X version -// that doesn't support CSR/SIP -// 0-127 = Valid values (as of 11/2015) -// 128-255 = High bit set unexpectedly, but value still returned -INTN GetCsrStatus(VOID) { - CHAR8 *CsrValues; - UINTN CsrLength; - EFI_GUID CsrGuid = CSR_GUID; - EFI_STATUS Status; - - Status = EfivarGetRaw(&CsrGuid, L"csr-active-config", &CsrValues, &CsrLength); - if (Status == EFI_SUCCESS) { - if (CsrLength == 4) { - return CsrValues[0]; - } else { - return -2; +// information. +EFI_STATUS GetCsrStatus(UINT32 *CsrStatus) { + UINT32 *ReturnValue; + UINTN CsrLength; + EFI_GUID CsrGuid = CSR_GUID; + EFI_STATUS Status = EFI_INVALID_PARAMETER; + + if (CsrStatus) { + Status = EfivarGetRaw(&CsrGuid, L"csr-active-config", (CHAR8**) &ReturnValue, &CsrLength); + if (Status == EFI_SUCCESS) { + if (CsrLength == 4) { + *CsrStatus = *ReturnValue; + } else { + Status = EFI_BAD_BUFFER_SIZE; + } } - } else { - return -1; + MyFreePool(ReturnValue); } + return Status; } // INTN GetCsrStatus() // Store string describing CSR status byte in gCsrStatus variable, which appears -// on the Info page. -VOID RecordgCsrStatus(INTN CsrStatus) { +// on the Info page. If DisplayMessage is TRUE, displays the new value of +// gCsrStatus on the screen for three seconds. +VOID RecordgCsrStatus(UINT32 CsrStatus, BOOLEAN DisplayMessage) { + EG_PIXEL BGColor; + + BGColor.b = 255; + BGColor.g = 175; + BGColor.r = 100; + BGColor.a = 0; + if (gCsrStatus == NULL) gCsrStatus = AllocateZeroPool(256 * sizeof(CHAR16)); switch (CsrStatus) { - case -2: - SPrint(gCsrStatus, 255, L" System Integrity Protection status is unrecognized"); - break; - case -1: - SPrint(gCsrStatus, 255, L"System Integrity Protection status is unrecorded"); - break; case SIP_ENABLED: SPrint(gCsrStatus, 255, L" System Integrity Protection is enabled (0x%02x)", CsrStatus); break; @@ -76,63 +74,37 @@ VOID RecordgCsrStatus(INTN CsrStatus) { default: SPrint(gCsrStatus, 255, L" System Integrity Protection status: 0x%02x", CsrStatus); } // switch + if (DisplayMessage) { + egDisplayMessage(gCsrStatus, &BGColor); + PauseSeconds(3); + } // if } // VOID RecordgCsrStatus // Find the current CSR status and reset it to the next one in the // GlobalConfig.CsrValues list, or to the first value if the current // value is not on the list. // Returns the value to which the CSR is being set. -INTN RotateCsrValue(VOID) { - INTN CurrentValue; - UINTN Index = 0; - CHAR16 *CurrentValueAsString = NULL; - CHAR16 *TargetValueAsString = NULL; - CHAR16 *ListItem; - CHAR8 TargetCsr[4]; - EFI_GUID CsrGuid = CSR_GUID; - EFI_STATUS Status; - EG_PIXEL BGColor; - - BGColor.b = 255; - BGColor.g = 175; - BGColor.r = 100; - BGColor.a = 0; - CurrentValue = GetCsrStatus(); - if ((CurrentValue >= 0) && GlobalConfig.CsrValues) { - CurrentValueAsString = PoolPrint(L"%02x", CurrentValue); - while (TargetValueAsString == NULL) { - ListItem = FindCommaDelimited(GlobalConfig.CsrValues, Index++); - if (ListItem) { - if (MyStriCmp(ListItem, CurrentValueAsString)) { - TargetValueAsString = FindCommaDelimited(GlobalConfig.CsrValues, Index); - if (TargetValueAsString == NULL) - TargetValueAsString = FindCommaDelimited(GlobalConfig.CsrValues, 0); - } - } else { - TargetValueAsString = FindCommaDelimited(GlobalConfig.CsrValues, 0); - } // if/else - MyFreePool(ListItem); - } // while - TargetCsr[0] = (CHAR8) StrToHex(TargetValueAsString, 0, 2); - Status = EfivarSetRaw(&CsrGuid, L"csr-active-config", TargetCsr, 4, TRUE); - if (Status == EFI_SUCCESS) { - switch (TargetCsr[0]) { - case SIP_ENABLED: - egDisplayMessage(PoolPrint(L"Set System Integrity Protection to enabled (0x%x)", (UINTN) TargetCsr[0]), &BGColor); - break; - case SIP_DISABLED: - egDisplayMessage(PoolPrint(L"Set System Integrity Protection status to disabled (0x%x)", (UINTN) TargetCsr[0]), &BGColor); - break; - default: - egDisplayMessage(PoolPrint(L"Set System Integrity Protection status to 0x%x", (UINTN) TargetCsr[0]), &BGColor); - } - RecordgCsrStatus((INTN) TargetCsr[0]); +VOID RotateCsrValue(VOID) { + UINT32 CurrentValue; + UINT32_LIST *ListItem; + UINT32 TargetCsr; + EFI_GUID CsrGuid = CSR_GUID; + EFI_STATUS Status; + + Status = GetCsrStatus(&CurrentValue); + if ((Status == EFI_SUCCESS) && GlobalConfig.CsrValues) { + ListItem = GlobalConfig.CsrValues; + while ((ListItem != NULL) && (ListItem->Value != CurrentValue)) + ListItem = ListItem->Next; + if (ListItem == NULL || ListItem->Next == NULL) { + TargetCsr = GlobalConfig.CsrValues->Value; } else { - egDisplayMessage(L"Error setting System Integrity Protection status", &BGColor); + TargetCsr = ListItem->Next->Value; } - PauseSeconds(3); + Status = EfivarSetRaw(&CsrGuid, L"csr-active-config", (CHAR8 *) &TargetCsr, 4, TRUE); + if (Status == EFI_SUCCESS) + RecordgCsrStatus(TargetCsr, TRUE); } // if - return (INTN) TargetCsr[0]; } // INTN RotateCsrValue() @@ -166,7 +138,7 @@ EFI_STATUS SetAppleOSInfo() { Status = refit_call3_wrapper(BS->LocateProtocol, &apple_set_os_guid, NULL, (VOID**) &SetOs); - // Not a Mac, so ignore the call.... + // If not a Mac, ignore the call.... if ((Status != EFI_SUCCESS) || (!SetOs)) return EFI_SUCCESS; diff --git a/refind/apple.h b/refind/apple.h index 33fd5b2..17ed155 100644 --- a/refind/apple.h +++ b/refind/apple.h @@ -18,9 +18,41 @@ * */ +#ifndef __APPLE_H_ +#define __APPLE_H_ + +// The constants related to Apple's System Integrity Protection (SIP).... +#define CSR_GUID { 0x7c436110, 0xab2a, 0x4bbb, { 0xa8, 0x80, 0xfe, 0x41, 0x99, 0x5c, 0x9f, 0x82 } }; +// These codes are returned in the first byte of the csr-active-config variable +#define CSR_ALLOW_UNTRUSTED_KEXTS 0x01 +#define CSR_ALLOW_UNRESTRICTED_FS 0x02 +#define CSR_ALLOW_TASK_FOR_PID 0x04 +#define CSR_ALLOW_KERNEL_DEBUGGER 0x08 +#define CSR_ALLOW_APPLE_INTERNAL 0x10 +#define CSR_ALLOW_UNRESTRICTED_DTRACE 0x20 +#define CSR_ALLOW_UNRESTRICTED_NVRAM 0x40 +#define CSR_END_OF_LIST 0xFFFFFFFF +// Some summaries.... +#define SIP_ENABLED CSR_ALLOW_APPLE_INTERNAL +#define SIP_DISABLED (CSR_ALLOW_UNRESTRICTED_NVRAM | \ + CSR_ALLOW_UNRESTRICTED_DTRACE | \ + CSR_ALLOW_APPLE_INTERNAL | \ + CSR_ALLOW_TASK_FOR_PID | \ + CSR_ALLOW_UNRESTRICTED_FS | \ + CSR_ALLOW_UNTRUSTED_KEXTS) +#define CSR_MAX_LEGAL_VALUE (CSR_ALLOW_UNTRUSTED_KEXTS | \ + CSR_ALLOW_UNRESTRICTED_FS | \ + CSR_ALLOW_TASK_FOR_PID | \ + CSR_ALLOW_KERNEL_DEBUGGER | \ + CSR_ALLOW_APPLE_INTERNAL | \ + CSR_ALLOW_UNRESTRICTED_DTRACE | \ + CSR_ALLOW_UNRESTRICTED_NVRAM) + extern CHAR16 *gCsrStatus; -INTN GetCsrStatus(VOID); -VOID RecordgCsrStatus(INTN CsrStatus); -INTN RotateCsrValue(VOID); +EFI_STATUS GetCsrStatus(UINT32 *CsrValue); +VOID RecordgCsrStatus(UINT32 CsrStatus, BOOLEAN DisplayMessage); +VOID RotateCsrValue(VOID); EFI_STATUS SetAppleOSInfo(); + +#endif \ No newline at end of file diff --git a/refind/config.c b/refind/config.c index e54e56b..f592eb9 100644 --- a/refind/config.c +++ b/refind/config.c @@ -62,6 +62,7 @@ #include "menu.h" #include "config.h" #include "screen.h" +#include "apple.h" #include "../include/refit_call_wrapper.h" #include "../mok/mok.h" @@ -377,6 +378,48 @@ static VOID HandleStrings(IN CHAR16 **TokenList, IN UINTN TokenCount, OUT CHAR16 } // for } // static VOID HandleStrings() +// Handle a parameter with a series of hexadecimal arguments, to replace or be added to a +// linked list of UINT32 values. Any item with a non-hexadecimal value is discarded, as is +// any value that exceeds MaxValue. If the first non-keyword token is "+", the new list is +// added to the existing Target; otherwise, the interpreted tokens replace the current +// Target. +static VOID HandleHexes(IN CHAR16 **TokenList, IN UINTN TokenCount, IN UINTN MaxValue, OUT UINT32_LIST **Target) { + UINTN InputIndex = 1, i; + UINT32 Value; + UINT32_LIST *EndOfList = NULL; + UINT32_LIST *NewEntry; + + if ((TokenCount > 2) && (StrCmp(TokenList[1], L"+") == 0)) { + InputIndex = 2; + EndOfList = *Target; + while (EndOfList && (EndOfList->Next != NULL)) { + EndOfList = EndOfList->Next; + } + } else { + EraseUint32List(Target); + } + + for (i = InputIndex; i < TokenCount; i++) { + if (IsValidHex(TokenList[i])) { + Value = (UINT32) StrToHex(TokenList[i], 0, 8); + if (Value <= MaxValue) { + NewEntry = AllocatePool(sizeof(UINT32_LIST)); + if (NewEntry) { + NewEntry->Value = Value; + NewEntry->Next = NULL; + if (EndOfList == NULL) { + EndOfList = NewEntry; + *Target = NewEntry; + } else { + EndOfList->Next = NewEntry; + EndOfList = NewEntry; + } // if/else + } // if allocated memory for NewEntry + } // if (Value < MaxValue) + } // if is valid hex value + } // for +} // static VOID HandleHexes() + // Convert TimeString (in "HH:MM" format) to a pure-minute format. Values should be // in the range from 0 (for 00:00, or midnight) to 1439 (for 23:59; aka LAST_MINUTE). // Any value outside that range denotes an error in the specification. Note that if @@ -707,7 +750,7 @@ VOID ReadConfig(CHAR16 *FileName) HandleString(TokenList, TokenCount, &(GlobalConfig.SpoofOSXVersion)); } else if (MyStriCmp(TokenList[0], L"csr_values")) { - HandleStrings(TokenList, TokenCount, &(GlobalConfig.CsrValues)); + HandleHexes(TokenList, TokenCount, CSR_MAX_LEGAL_VALUE, &(GlobalConfig.CsrValues)); } else if (MyStriCmp(TokenList[0], L"include") && (TokenCount == 2) && MyStriCmp(FileName, GlobalConfig.ConfigFilename)) { if (!MyStriCmp(TokenList[1], FileName)) { diff --git a/refind/global.h b/refind/global.h index a07e0c9..8acbf7d 100644 --- a/refind/global.h +++ b/refind/global.h @@ -148,25 +148,6 @@ #define ICON_SIZE_SMALL 1 #define ICON_SIZE_BIG 2 -// The constants related to Apple's System Integrity Protection (SIP).... -#define CSR_GUID { 0x7c436110, 0xab2a, 0x4bbb, { 0xa8, 0x80, 0xfe, 0x41, 0x99, 0x5c, 0x9f, 0x82 } }; -// These codes are returned in the first byte of the csr-active-config variable -#define CSR_ALLOW_UNTRUSTED_KEXTS 0x01 -#define CSR_ALLOW_UNRESTRICTED_FS 0x02 -#define CSR_ALLOW_TASK_FOR_PID 0x04 -#define CSR_ALLOW_KERNEL_DEBUGGER 0x08 -#define CSR_ALLOW_APPLE_INTERNAL 0x10 -#define CSR_ALLOW_UNRESTRICTED_DTRACE 0x20 -#define CSR_ALLOW_UNRESTRICTED_NVRAM 0x40 -// Some summaries.... -#define SIP_ENABLED CSR_ALLOW_APPLE_INTERNAL -#define SIP_DISABLED (CSR_ALLOW_UNRESTRICTED_NVRAM | \ - CSR_ALLOW_UNRESTRICTED_DTRACE | \ - CSR_ALLOW_APPLE_INTERNAL | \ - CSR_ALLOW_TASK_FOR_PID | \ - CSR_ALLOW_UNRESTRICTED_FS | \ - CSR_ALLOW_UNTRUSTED_KEXTS) - // Names of binaries that can manage MOKs.... #define MOK_NAMES L"MokManager.efi,HashTool.efi,HashTool-signed.efi,KeyTool.efi,KeyTool-signed.efi" // Directories to search for these MOK-managing programs. Note that SelfDir is @@ -204,6 +185,11 @@ // global types +typedef struct _uint32_list { + UINT32 Value; + struct _uint32_list *Next; +} UINT32_LIST; + typedef struct { UINT8 Flags; UINT8 StartCHS1; @@ -326,7 +312,7 @@ typedef struct { CHAR16 *DriverDirs; CHAR16 *IconsDir; CHAR16 *SpoofOSXVersion; - CHAR16 *CsrValues; + UINT32_LIST *CsrValues; UINTN ShowTools[NUM_TOOLS]; CHAR8 ScanFor[NUM_SCAN_OPTIONS]; // codes of types of loaders for which to scan } REFIT_CONFIG; diff --git a/refind/lib.c b/refind/lib.c index 46e2650..3a75cdf 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -2031,6 +2031,23 @@ BOOLEAN EjectMedia(VOID) { return (Ejected > 0); } // VOID EjectMedia() +// Returns TRUE if *Input contains nothing but valid hexadecimal characters, +// FALSE otherwise. Note that a leading "0x" is NOT acceptable in the input! +BOOLEAN IsValidHex(CHAR16 *Input) { + BOOLEAN IsHex = TRUE; + UINTN i = 0; + + while ((Input[i] != L'\0') && IsHex) { + if (!(((Input[i] >= L'0') && (Input[i] <= L'9')) || + ((Input[i] >= L'A') && (Input[i] <= L'F')) || + ((Input[i] >= L'a') && (Input[i] <= L'f')))) { + IsHex = FALSE; + } + i++; + } // while + return IsHex; +} // BOOLEAN IsValidHex() + // Converts consecutive characters in the input string into a // number, interpreting the string as a hexadecimal number, starting // at the specified position and continuing for the specified number @@ -2140,3 +2157,14 @@ EFI_GUID StringAsGuid(CHAR16 * InString) { BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2) { return (CompareMem(Guid1, Guid2, 16) == 0); } // BOOLEAN GuidsAreEqual() + +// Erase linked-list of UINT32 values.... +VOID EraseUint32List(UINT32_LIST **TheList) { + UINT32_LIST *NextItem; + + while (*TheList) { + NextItem = (*TheList)->Next; + FreePool(*TheList); + *TheList = NextItem; + } // while +} // EraseUin32List() diff --git a/refind/lib.h b/refind/lib.h index 376efd7..037605c 100644 --- a/refind/lib.h +++ b/refind/lib.h @@ -141,10 +141,13 @@ VOID MyFreePool(IN OUT VOID *Pointer); BOOLEAN EjectMedia(VOID); +BOOLEAN IsValidHex(CHAR16 *Input); UINT64 StrToHex(CHAR16 *Input, UINTN Position, UINTN NumChars); BOOLEAN IsGuid(CHAR16 *UnknownString); CHAR16 * GuidAsString(EFI_GUID *GuidData); EFI_GUID StringAsGuid(CHAR16 * InString); BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2); +VOID EraseUint32List(UINT32_LIST **TheList); + #endif \ No newline at end of file diff --git a/refind/main.c b/refind/main.c index f169086..6234a97 100644 --- a/refind/main.c +++ b/refind/main.c @@ -187,12 +187,12 @@ struct LOADER_LIST { static VOID AboutrEFInd(VOID) { - CHAR16 *FirmwareVendor; - INTN CsrStatus; + CHAR16 *FirmwareVendor; + UINT32 CsrStatus; if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.9.2.6"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.9.2.7"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2015 Roderick W. Smith"); @@ -210,10 +210,10 @@ static VOID AboutrEFInd(VOID) #else AddMenuInfoLine(&AboutMenu, L" Platform: unknown"); #endif - CsrStatus = GetCsrStatus(); - RecordgCsrStatus(CsrStatus); - if ((CsrStatus == -2) || (CsrStatus >= 0)) + if (GetCsrStatus(&CsrStatus) == EFI_SUCCESS) { + RecordgCsrStatus(CsrStatus, FALSE); AddMenuInfoLine(&AboutMenu, gCsrStatus); + } FirmwareVendor = StrDuplicate(ST->FirmwareVendor); LimitStringLength(FirmwareVendor, MAX_LINE_LENGTH); // More than ~65 causes empty info page on 800x600 display AddMenuInfoLine(&AboutMenu, PoolPrint(L" Firmware: %s %d.%02d", FirmwareVendor, ST->FirmwareRevision >> 16, @@ -1912,6 +1912,7 @@ static VOID ScanForTools(VOID) { UINTN i, j, VolumeIndex; UINT64 osind; CHAR8 *b = 0; + UINT32 CsrValue; MokLocations = StrDuplicate(MOK_LOCATIONS); if (MokLocations != NULL) @@ -2043,7 +2044,7 @@ static VOID ScanForTools(VOID) { break; case TAG_CSR_ROTATE: - if ((GetCsrStatus() >= 0) && (GlobalConfig.CsrValues)) { + if ((GetCsrStatus(&CsrValue) == EFI_SUCCESS) && (GlobalConfig.CsrValues)) { TempMenuEntry = CopyMenuEntry(&MenuEntryRotateCsr); TempMenuEntry->Image = BuiltinIcon(BUILTIN_ICON_FUNC_CSR_ROTATE); AddMenuEntry(&MainMenu, TempMenuEntry);