VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageModifyNvram.cpp@ 91571

Last change on this file since 91571 was 91491, checked in by vboxsync, 3 years ago

FE/VBoxManage: Add sub-command to enroll the default VBox platform key for secure boot, bugref:9580

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1/* $Id: VBoxManageModifyNvram.cpp 91491 2021-09-30 08:33:40Z vboxsync $ */
2/** @file
3 * VBoxManage - The nvram control related commands.
4 */
5
6/*
7 * Copyright (C) 2021 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef VBOX_ONLY_DOCS
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#include <VBox/com/com.h>
25#include <VBox/com/array.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/errorprint.h>
28#include <VBox/com/VirtualBox.h>
29
30#include <iprt/errcore.h>
31#include <iprt/path.h>
32#include <iprt/param.h>
33#include <iprt/string.h>
34#include <iprt/ctype.h>
35#include <iprt/stream.h>
36#include <iprt/file.h>
37#include <iprt/getopt.h>
38#include <iprt/uuid.h>
39#include <VBox/log.h>
40
41#include "VBoxManage.h"
42using namespace com;
43
44
45// funcs
46///////////////////////////////////////////////////////////////////////////////
47
48
49/**
50 * Handles the 'modifynvram myvm inituefivarstore' sub-command.
51 * @returns Exit code.
52 * @param a The handler argument package.
53 * @param nvram Reference to the NVRAM store interface.
54 */
55static RTEXITCODE handleModifyNvramInitUefiVarStore(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
56{
57 RT_NOREF(a);
58
59 CHECK_ERROR2I_RET(nvramStore, InitUefiVariableStore(0 /*aSize*/), RTEXITCODE_FAILURE);
60 return RTEXITCODE_SUCCESS;
61}
62
63
64/**
65 * Handles the 'modifynvram myvm enrollmssignatures' sub-command.
66 * @returns Exit code.
67 * @param a The handler argument package.
68 * @param nvram Reference to the NVRAM store interface.
69 */
70static RTEXITCODE handleModifyNvramEnrollMsSignatures(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
71{
72 RT_NOREF(a);
73
74 ComPtr<IUefiVariableStore> uefiVarStore;
75 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
76
77 CHECK_ERROR2I_RET(uefiVarStore, EnrollDefaultMsSignatures(), RTEXITCODE_FAILURE);
78 return RTEXITCODE_SUCCESS;
79}
80
81
82/**
83 * Handles the 'modifynvram myvm enrollpk' sub-command.
84 * @returns Exit code.
85 * @param a The handler argument package.
86 * @param nvram Reference to the NVRAM store interface.
87 */
88static RTEXITCODE handleModifyNvramEnrollPlatformKey(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
89{
90 static const RTGETOPTDEF s_aOptions[] =
91 {
92 /* common options */
93 { "--platform-key", 'p', RTGETOPT_REQ_STRING },
94 { "--owner-uuid", 'f', RTGETOPT_REQ_STRING }
95 };
96
97 const char *pszPlatformKey = NULL;
98 const char *pszOwnerUuid = NULL;
99
100 RTGETOPTSTATE GetState;
101 int vrc = RTGetOptInit(&GetState, a->argc - 2, &a->argv[2], s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
102 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
103
104 int c;
105 RTGETOPTUNION ValueUnion;
106 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
107 {
108 switch (c)
109 {
110 case 'p':
111 pszPlatformKey = ValueUnion.psz;
112 break;
113 case 'f':
114 pszOwnerUuid = ValueUnion.psz;
115 break;
116 default:
117 return errorGetOpt(c, &ValueUnion);
118 }
119 }
120
121 if (!pszPlatformKey)
122 return errorSyntax("No platform key file path was given to \"enrollpk\"");
123 if (!pszOwnerUuid)
124 return errorSyntax("No owner UUID was given to \"enrollpk\"");
125
126 RTFILE hPkFile;
127 vrc = RTFileOpen(&hPkFile, pszPlatformKey, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
128 if (RT_SUCCESS(vrc))
129 {
130 uint64_t cbSize;
131 vrc = RTFileQuerySize(hPkFile, &cbSize);
132 if (RT_SUCCESS(vrc))
133 {
134 if (cbSize <= _32K)
135 {
136 SafeArray<BYTE> aPk((size_t)cbSize);
137 vrc = RTFileRead(hPkFile, aPk.raw(), (size_t)cbSize, NULL);
138 if (RT_SUCCESS(vrc))
139 {
140 RTFileClose(hPkFile);
141
142 ComPtr<IUefiVariableStore> uefiVarStore;
143 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
144 CHECK_ERROR2I_RET(uefiVarStore, EnrollPlatformKey(ComSafeArrayAsInParam(aPk), Bstr(pszOwnerUuid).raw()), RTEXITCODE_FAILURE);
145 return RTEXITCODE_SUCCESS;
146 }
147 else
148 RTMsgError("Cannot read contents of file \"%s\": %Rrc", pszPlatformKey, vrc);
149 }
150 else
151 RTMsgError("File \"%s\" is bigger than 32KByte", pszPlatformKey);
152 }
153 else
154 RTMsgError("Cannot get size of file \"%s\": %Rrc", pszPlatformKey, vrc);
155
156 RTFileClose(hPkFile);
157 }
158 else
159 RTMsgError("Cannot open file \"%s\": %Rrc", pszPlatformKey, vrc);
160
161 return RTEXITCODE_FAILURE;
162}
163
164
165/**
166 * Handles the 'modifynvram myvm enrollorclpk' sub-command.
167 * @returns Exit code.
168 * @param a The handler argument package.
169 * @param nvram Reference to the NVRAM store interface.
170 */
171static RTEXITCODE handleModifyNvramEnrollOraclePlatformKey(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
172{
173 RT_NOREF(a);
174
175 ComPtr<IUefiVariableStore> uefiVarStore;
176 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
177
178 CHECK_ERROR2I_RET(uefiVarStore, EnrollOraclePlatformKey(), RTEXITCODE_FAILURE);
179 return RTEXITCODE_SUCCESS;
180}
181
182
183/**
184 * Handles the 'modifynvram myvm listvars' sub-command.
185 * @returns Exit code.
186 * @param a The handler argument package.
187 * @param nvram Reference to the NVRAM store interface.
188 */
189static RTEXITCODE handleModifyNvramListUefiVars(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
190{
191 RT_NOREF(a);
192
193 ComPtr<IUefiVariableStore> uefiVarStore;
194 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
195
196 com::SafeArray<BSTR> aNames;
197 com::SafeArray<BSTR> aOwnerGuids;
198 CHECK_ERROR2I_RET(uefiVarStore, QueryVariables(ComSafeArrayAsOutParam(aNames), ComSafeArrayAsOutParam(aOwnerGuids)), RTEXITCODE_FAILURE);
199 for (size_t i = 0; i < aNames.size(); i++)
200 {
201 Bstr strName = aNames[i];
202 Bstr strOwnerGuid = aOwnerGuids[i];
203
204 RTPrintf("%-32ls {%ls}\n", strName.raw(), strOwnerGuid.raw());
205 }
206
207 return RTEXITCODE_SUCCESS;
208}
209
210
211/**
212 * Handles the 'modifynvram myvm queryvar' sub-command.
213 * @returns Exit code.
214 * @param a The handler argument package.
215 * @param nvram Reference to the NVRAM store interface.
216 */
217static RTEXITCODE handleModifyNvramQueryUefiVar(HandlerArg *a, ComPtr<INvramStore> &nvramStore)
218{
219 static const RTGETOPTDEF s_aOptions[] =
220 {
221 /* common options */
222 { "--name", 'n', RTGETOPT_REQ_STRING },
223 { "--filename", 'f', RTGETOPT_REQ_STRING }
224 };
225
226 const char *pszVarName = NULL;
227 const char *pszVarDataFilename = NULL;
228
229 RTGETOPTSTATE GetState;
230 int vrc = RTGetOptInit(&GetState, a->argc - 2, &a->argv[2], s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
231 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
232
233 int c;
234 RTGETOPTUNION ValueUnion;
235 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
236 {
237 switch (c)
238 {
239 case 'n':
240 pszVarName = ValueUnion.psz;
241 break;
242 case 'f':
243 pszVarDataFilename = ValueUnion.psz;
244 break;
245 default:
246 return errorGetOpt(c, &ValueUnion);
247 }
248 }
249
250 if (!pszVarName)
251 return errorSyntax("No variable name was given to \"queryvar\"");
252
253 ComPtr<IUefiVariableStore> uefiVarStore;
254 CHECK_ERROR2I_RET(nvramStore, COMGETTER(UefiVariableStore)(uefiVarStore.asOutParam()), RTEXITCODE_FAILURE);
255
256 Bstr strOwnerGuid;
257 com::SafeArray<UefiVariableAttributes_T> aVarAttrs;
258 com::SafeArray<BYTE> aData;
259 CHECK_ERROR2I_RET(uefiVarStore, QueryVariableByName(Bstr(pszVarName).raw(), strOwnerGuid.asOutParam(),
260 ComSafeArrayAsOutParam(aVarAttrs), ComSafeArrayAsOutParam(aData)),
261 RTEXITCODE_FAILURE);
262
263 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
264 if (!pszVarDataFilename)
265 {
266 RTPrintf("%s {%ls}:\n"
267 "%.*Rhxd\n", pszVarName, strOwnerGuid.raw(), aData.size(), aData.raw());
268 }
269 else
270 {
271 /* Just write the data to the file. */
272 RTFILE hFile = NIL_RTFILE;
273 vrc = RTFileOpen(&hFile, pszVarDataFilename, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
274 if (RT_SUCCESS(vrc))
275 {
276 vrc = RTFileWrite(hFile, aData.raw(), aData.size(), NULL /*pcbWritten*/);
277 if (RT_FAILURE(vrc))
278 rcExit = RTMsgErrorExitFailure("Error writing to '%s': %Rrc", pszVarDataFilename, vrc);
279
280 RTFileClose(hFile);
281 }
282 else
283 rcExit = RTMsgErrorExitFailure("Error opening '%s': %Rrc", pszVarDataFilename, vrc);
284 }
285
286 return rcExit;
287}
288
289
290/**
291 * Handles the 'modifynvram' command.
292 * @returns Exit code.
293 * @param a The handler argument package.
294 */
295RTEXITCODE handleModifyNvram(HandlerArg *a)
296{
297 HRESULT rc = S_OK;
298 ComPtr<IMachine> machine;
299 ComPtr<INvramStore> nvramStore;
300
301 if (a->argc < 2)
302 return errorNoSubcommand();
303
304 /* try to find the given machine */
305 CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
306 machine.asOutParam()), RTEXITCODE_FAILURE);
307
308 /* open a session for the VM (new or shared) */
309 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), RTEXITCODE_FAILURE);
310
311 /* get the mutable session machine */
312 a->session->COMGETTER(Machine)(machine.asOutParam());
313 rc = machine->COMGETTER(NonVolatileStore)(nvramStore.asOutParam());
314 if (FAILED(rc)) goto leave;
315
316 if (!strcmp(a->argv[1], "inituefivarstore"))
317 rc = handleModifyNvramInitUefiVarStore(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
318 else if (!strcmp(a->argv[1], "enrollmssignatures"))
319 rc = handleModifyNvramEnrollMsSignatures(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
320 else if (!strcmp(a->argv[1], "enrollpk"))
321 rc = handleModifyNvramEnrollPlatformKey(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
322 else if (!strcmp(a->argv[1], "enrollorclpk"))
323 rc = handleModifyNvramEnrollOraclePlatformKey(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
324 else if (!strcmp(a->argv[1], "listvars"))
325 rc = handleModifyNvramListUefiVars(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
326 else if (!strcmp(a->argv[1], "queryvar"))
327 rc = handleModifyNvramQueryUefiVar(a, nvramStore) == RTEXITCODE_SUCCESS ? S_OK : E_FAIL;
328 else
329 return errorUnknownSubcommand(a->argv[0]);
330
331 /* commit changes */
332 if (SUCCEEDED(rc))
333 CHECK_ERROR(machine, SaveSettings());
334
335leave:
336 /* it's important to always close sessions */
337 a->session->UnlockMachine();
338
339 return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
340}
341
342#endif /* !VBOX_ONLY_DOCS */
343
Note: See TracBrowser for help on using the repository browser.

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