Modified SIP/CSR feature to work ON MACS when the csr-active-config
[refind] / refind / apple.c
1 /*
2 * refind/apple.c
3 * Functions specific to Apple computers
4 *
5 * Copyright (c) 2015 Roderick W. Smith
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "global.h"
23 #include "config.h"
24 #include "lib.h"
25 #include "screen.h"
26 #include "apple.h"
27 #include "mystrings.h"
28 #include "refit_call_wrapper.h"
29
30 CHAR16 gCsrStatus[256];
31
32 // Get CSR (Apple's System Integrity Protection [SIP], or "rootless") status
33 // information. If the variable is not present and the firmware is Apple, fake
34 // it and claim it's enabled, since that's how OS X 10.11 treats a system with
35 // the variable absent.
36 EFI_STATUS GetCsrStatus(UINT32 *CsrStatus) {
37 UINT32 *ReturnValue = NULL;
38 UINTN CsrLength;
39 EFI_GUID CsrGuid = CSR_GUID;
40 EFI_STATUS Status = EFI_INVALID_PARAMETER;
41
42 if (CsrStatus) {
43 Status = EfivarGetRaw(&CsrGuid, L"csr-active-config", (CHAR8**) &ReturnValue, &CsrLength);
44 if (Status == EFI_SUCCESS) {
45 if (CsrLength == 4) {
46 *CsrStatus = *ReturnValue;
47 } else {
48 Status = EFI_BAD_BUFFER_SIZE;
49 SPrint(gCsrStatus, 255, L" Unknown System Integrity Protection version");
50 }
51 MyFreePool(ReturnValue);
52 } else if ((Status == EFI_NOT_FOUND) && (StriSubCmp(L"Apple", ST->FirmwareVendor))) {
53 *CsrStatus = SIP_ENABLED;
54 Status = EFI_SUCCESS;
55 } // if (Status == EFI_SUCCESS)
56 } // if (CsrStatus)
57 return Status;
58 } // INTN GetCsrStatus()
59
60 // Store string describing CSR status value in gCsrStatus variable, which appears
61 // on the Info page. If DisplayMessage is TRUE, displays the new value of
62 // gCsrStatus on the screen for three seconds.
63 VOID RecordgCsrStatus(UINT32 CsrStatus, BOOLEAN DisplayMessage) {
64 EG_PIXEL BGColor;
65
66 BGColor.b = 255;
67 BGColor.g = 175;
68 BGColor.r = 100;
69 BGColor.a = 0;
70
71 switch (CsrStatus) {
72 case SIP_ENABLED:
73 SPrint(gCsrStatus, 255, L" System Integrity Protection is enabled (0x%02x)", CsrStatus);
74 break;
75 case SIP_DISABLED:
76 SPrint(gCsrStatus, 255, L" System Integrity Protection is disabled (0x%02x)", CsrStatus);
77 break;
78 default:
79 SPrint(gCsrStatus, 255, L" System Integrity Protection status: 0x%02x", CsrStatus);
80 } // switch
81 if (DisplayMessage) {
82 egDisplayMessage(gCsrStatus, &BGColor);
83 PauseSeconds(3);
84 } // if
85 } // VOID RecordgCsrStatus()
86
87 // Find the current CSR status and reset it to the next one in the
88 // GlobalConfig.CsrValues list, or to the first value if the current
89 // value is not on the list.
90 VOID RotateCsrValue(VOID) {
91 UINT32 CurrentValue, TargetCsr;
92 UINT32_LIST *ListItem;
93 EFI_GUID CsrGuid = CSR_GUID;
94 EFI_STATUS Status;
95
96 Status = GetCsrStatus(&CurrentValue);
97 if ((Status == EFI_SUCCESS) && GlobalConfig.CsrValues) {
98 ListItem = GlobalConfig.CsrValues;
99 while ((ListItem != NULL) && (ListItem->Value != CurrentValue))
100 ListItem = ListItem->Next;
101 if (ListItem == NULL || ListItem->Next == NULL) {
102 TargetCsr = GlobalConfig.CsrValues->Value;
103 } else {
104 TargetCsr = ListItem->Next->Value;
105 }
106 Status = EfivarSetRaw(&CsrGuid, L"csr-active-config", (CHAR8 *) &TargetCsr, 4, TRUE);
107 if (Status == EFI_SUCCESS)
108 RecordgCsrStatus(TargetCsr, TRUE);
109 else
110 SPrint(gCsrStatus, 255, L" Error setting System Integrity Protection code.");
111 } // if
112 } // VOID RotateCsrValue()
113
114
115 /*
116 * The below definitions and SetAppleOSInfo() function are based on a GRUB patch
117 * by Andreas Heider:
118 * https://lists.gnu.org/archive/html/grub-devel/2013-12/msg00442.html
119 */
120
121 #define EFI_APPLE_SET_OS_PROTOCOL_GUID \
122 { 0xc5c5da95, 0x7d5c, 0x45e6, \
123 { 0xb2, 0xf1, 0x3f, 0xd5, 0x2b, 0xb1, 0x00, 0x77 } \
124 }
125
126 typedef struct EfiAppleSetOsInterface {
127 UINT64 Version;
128 EFI_STATUS EFIAPI (*SetOsVersion) (IN CHAR8 *Version);
129 EFI_STATUS EFIAPI (*SetOsVendor) (IN CHAR8 *Vendor);
130 } EfiAppleSetOsInterface;
131
132 // Function to tell the firmware that OS X is being launched. This is
133 // required to work around problems on some Macs that don't fully
134 // initialize some hardware (especially video displays) when third-party
135 // OSes are launched in EFI mode.
136 EFI_STATUS SetAppleOSInfo() {
137 CHAR16 *AppleOSVersion = NULL;
138 CHAR8 *AppleOSVersion8 = NULL;
139 EFI_STATUS Status;
140 EFI_GUID apple_set_os_guid = EFI_APPLE_SET_OS_PROTOCOL_GUID;
141 EfiAppleSetOsInterface *SetOs = NULL;
142
143 Status = refit_call3_wrapper(BS->LocateProtocol, &apple_set_os_guid, NULL, (VOID**) &SetOs);
144
145 // If not a Mac, ignore the call....
146 if ((Status != EFI_SUCCESS) || (!SetOs))
147 return EFI_SUCCESS;
148
149 if ((SetOs->Version != 0) && GlobalConfig.SpoofOSXVersion) {
150 AppleOSVersion = StrDuplicate(L"Mac OS X");
151 MergeStrings(&AppleOSVersion, GlobalConfig.SpoofOSXVersion, ' ');
152 if (AppleOSVersion) {
153 AppleOSVersion8 = AllocateZeroPool((StrLen(AppleOSVersion) + 1) * sizeof(CHAR8));
154 UnicodeStrToAsciiStr(AppleOSVersion, AppleOSVersion8);
155 if (AppleOSVersion8) {
156 Status = refit_call1_wrapper (SetOs->SetOsVersion, AppleOSVersion8);
157 if (!EFI_ERROR(Status))
158 Status = EFI_SUCCESS;
159 MyFreePool(AppleOSVersion8);
160 } else {
161 Status = EFI_OUT_OF_RESOURCES;
162 Print(L"Out of resources in SetAppleOSInfo!\n");
163 }
164 if ((Status == EFI_SUCCESS) && (SetOs->Version == 2))
165 Status = refit_call1_wrapper (SetOs->SetOsVendor, (CHAR8 *) "Apple Inc.");
166 MyFreePool(AppleOSVersion);
167 } // if (AppleOSVersion)
168 } // if
169 if (Status != EFI_SUCCESS)
170 Print(L"Unable to set firmware boot type!\n");
171
172 return (Status);
173 } // EFI_STATUS SetAppleOSInfo()