aboutsummaryrefslogtreecommitdiffstats
path: root/Loader.c
blob: 1f9201a72eb785fb1f3cb1e89f400ba0c4a76bca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * Copyright 2012 <James.Bottomley@HansenPartnership.com>
 *
 * see COPYING file
 *
 * Simple elf loader based on Intel TianoCore
 */

#include <efi.h>
#include <efilib.h>

#include <simple_file.h>
#include <pecoff.h>
#include <sha256.h>
#include <variables.h>
#include <console.h>
#include <efiauthenticated.h>
#include <guid.h>
#include <execute.h>

CHAR16 *loader = L"\\linux-loader.efi";

/* get the user's permission to boot the image */
int ask_to_boot(void)
{
	return console_yes_no( (CHAR16 *[]) {
		L"WARNING: This Binary is unsigned (and should be a Linux boot loader)",
		L"",
		L"Are you sure you wish to run an unsigned binary",
		L"in a secure environment?",
		L"",
		L"To avoid this question in future place the platform into setup mode",
		L"See http://www.linuxfoundation.org/uefi",
		L"And reboot.",
		NULL,
	});
}
/* Get the user's permission to install the image signature */
static int
ask_install_keys(void)
{
	/* first check to see if the key is already present */
	return console_yes_no( (CHAR16 *[]){ 
		L"You are in Setup Mode",
		L"",
		L"Do you wish me to install the signature",
		L"of the binary into the allowed signatures database?",
		L"",
		L"If you say \"yes\" here, the platform will no longer ask permission",
		L"to run the binary on every boot",
		NULL
	});
}

EFI_STATUS
efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
	EFI_STATUS efi_status;
	UINT8 SecureBoot = 0, SetupMode = 0;
	UINTN DataSize = sizeof(SecureBoot);
	EFI_FILE *file;
	EFI_LOADED_IMAGE *li;
	EFI_DEVICE_PATH *loadpath = NULL;
	CHAR16 *PathName = NULL;
	EFI_HANDLE loader_handle;

	InitializeLib(image, systab);

	efi_status = RT->GetVariable(L"SecureBoot", &GV_GUID, NULL, &DataSize, &SecureBoot);

	if (efi_status != EFI_SUCCESS) {
		Print(L"Not a Secure Boot Platform %d\n", efi_status);
	} else	if (!SecureBoot) {
		Print(L"Secure Boot Disabled\n");
		DataSize = sizeof(SetupMode);
	}

	RT->GetVariable(L"SetupMode", &GV_GUID, NULL, &DataSize, &SetupMode);

	efi_status = BS->HandleProtocol(image, &IMAGE_PROTOCOL, (VOID **)&li);
	if (efi_status != EFI_SUCCESS) {
		Print(L"Failed to init loaded image protocol: %d\n", efi_status);
		return efi_status;
	}

	efi_status = generate_path(loader, li, &loadpath, &PathName);
	if (efi_status != EFI_SUCCESS) {
		Print(L"Unable to generate load path for %s: %d\n", loader,
		      efi_status);
		return efi_status;
	}

	if (!SetupMode) {
		efi_status = BS->LoadImage(FALSE, image, loadpath, NULL,
					   0, &loader_handle);
		if (efi_status == EFI_SUCCESS) {
			/* Image validates - start it */
			Print(L"Starting file via StartImage\n");
			BS->StartImage(loader_handle, NULL, NULL);
			BS->UnloadImage(loader_handle);
			return EFI_SUCCESS;
		} else {
			Print(L"Failed to load the image: %d\n", efi_status);
		}
	}

	if (SecureBoot) {
		if (ask_to_boot() == 0) {
			/* user told us not to boot this */
			Print(L"Refusing to boot %s\n", loader);
			return EFI_ACCESS_DENIED;
		}
		Print(L"Booting %s with Present User Authorisation\n", loader);
	}
	efi_status = simple_file_open(image, loader, &file, EFI_FILE_MODE_READ);
	if (efi_status != EFI_SUCCESS) {
		Print(L"Failed to open %s\n", loader);
		return efi_status;
	}

	/* We're in setup mode and the User asked us to add the signature
	 * of this binary to the authorized signatures database */
	if (SetupMode) {
		UINT8 hash[SHA256_DIGEST_SIZE];
		int i;

		sha256_get_pecoff_digest(image, loader, hash);
		Print(L"HASH IS ");
		for (i=0; i<SHA256_DIGEST_SIZE; i++)
			Print(L"%02x", hash[i]);
		Print(L"\n");

		if (find_in_variable_esl(L"db", SIG_DB, hash, SHA256_DIGEST_SIZE) == EFI_SUCCESS)
			goto dont_ask;

		if (ask_install_keys()) {
			UINT8 sig[sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + SHA256_DIGEST_SIZE];
			EFI_SIGNATURE_LIST *l = (void *)sig;
			EFI_SIGNATURE_DATA *d = (void *)(sig + sizeof(EFI_SIGNATURE_LIST));
			SetMem(sig, sizeof(sig), 0);
			l->SignatureType = EFI_CERT_SHA256_GUID;
			l->SignatureListSize = sizeof(sig);
			l->SignatureSize = 16 +32; /* UEFI defined */
			CopyMem(&d->SignatureData, hash, sizeof(hash));

			efi_status = SetSecureVariable(L"db", sig, sizeof(sig), SIG_DB, EFI_VARIABLE_APPEND_WRITE, 0);
			if (efi_status != EFI_SUCCESS) {
				Print(L"Failed to add signature to db: %s\n", efi_status);
				return efi_status;
			}
		}
	dont_ask:
		;
	}

	efi_status = pecoff_execute_image(file, loader, image, systab);
	simple_file_close(file);

	return efi_status;
}