From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1aPBrt-0005HR-Hi for mharc-grub-devel@gnu.org; Fri, 29 Jan 2016 11:25:53 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57526) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPBro-0005HD-78 for grub-devel@gnu.org; Fri, 29 Jan 2016 11:25:51 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aPBrk-0004LM-CW for grub-devel@gnu.org; Fri, 29 Jan 2016 11:25:48 -0500 Received: from mail-yk0-x22a.google.com ([2607:f8b0:4002:c07::22a]:35105) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aPBrk-0004LI-48 for grub-devel@gnu.org; Fri, 29 Jan 2016 11:25:44 -0500 Received: by mail-yk0-x22a.google.com with SMTP id r207so31071484ykd.2 for ; Fri, 29 Jan 2016 08:25:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; bh=9+IvJ+jM+4zCZlMmmE1SYAqkStIqhZtCO6+O5gaa4Ys=; b=k1wYyM2sbiww0Eb+53Vcd8BAwQ3d4GRBCg9/Gsw8EKDIxBn3cNOLv3BApArwTojVLc 0CqjpeHio/Yqa/QnvweKH0kAxK9F98/2kSJPO4zX05w7hM/PjCedY1nl3HNsTpTGxBZq 1CIL9pYfOnMYiqzNNHpE92lM2w+IQyW6s02Gk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to:content-type; bh=9+IvJ+jM+4zCZlMmmE1SYAqkStIqhZtCO6+O5gaa4Ys=; b=lLqGxxv4Z8fkIpfP1jRffgqiVubGu1BfIhIBpr5lmvbpO/DpU1Xa7tOvTf89MVYkqc Ex+YbR6+dKBIQLHEEUrNpbMMMK6x1geJNKhlF9suWtMsVwYOum+fpbWqWTQ7acnIxgka PcQG52xzH6CD55hG4knUOoFaR58KUYDJNQgu3Y8lvX8krE53Ukuv6Vtx0VikaNk/rk7T hqkcclozYl5dnVKpjNk59tNK9mb6XZvdo02BQENX8rXNDtnGZuR9BRD2F5tcDtNbxeCJ AlvcLoGDQkI6X19T/9JQGDc0uTBuIeEi2/Bfv3UFGdjOixwVKVLSg0qDUsnEbW+KEZYy Kn9g== X-Gm-Message-State: AG10YORHR598mF0WMlp1s/780DdjiAFNg0hCTfeUvgNUWJhuSipMg22AstqHkO1edkZkyWyTM/nkVtgSQGq1LPLZ MIME-Version: 1.0 X-Received: by 10.129.134.69 with SMTP id w66mr5466805ywf.193.1454084743256; Fri, 29 Jan 2016 08:25:43 -0800 (PST) Received: by 10.13.198.71 with HTTP; Fri, 29 Jan 2016 08:25:43 -0800 (PST) In-Reply-To: References: <563999B9.7020108@gmail.com> <5643845E.9060204@gmail.com> <5646B275.5040707@gmail.com> <56586384.1030504@gmail.com> <565ABE97.5060109@gmail.com> <56607141.8030209@gmail.com> <566BDC9A.2080501@gmail.com> Date: Fri, 29 Jan 2016 16:25:43 +0000 Message-ID: Subject: Re: Grub get and set efi variables From: Ignat Korchagin To: The development of GNU GRUB Content-Type: multipart/alternative; boundary=001a114f098c988bba052a7b7c7d X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:4002:c07::22a X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 29 Jan 2016 16:25:51 -0000 --001a114f098c988bba052a7b7c7d Content-Type: text/plain; charset=UTF-8 Hi. Are we still considering this? On Mon, Dec 14, 2015 at 11:17 AM, Ignat Korchagin wrote: > Sorry, pasted wrong file. Here is the correct one: > > diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def > index 0cc40bb..aa7b927 100644 > --- a/grub-core/Makefile.core.def > +++ b/grub-core/Makefile.core.def > @@ -735,6 +735,12 @@ module = { > }; > > module = { > + name = efivar; > + efi = commands/efi/efivar.c; > + enable = efi; > +}; > + > +module = { > name = blocklist; > common = commands/blocklist.c; > }; > diff --git a/grub-core/commands/efi/efivar.c > b/grub-core/commands/efi/efivar.c > new file mode 100644 > index 0000000..7fe7bda > --- /dev/null > +++ b/grub-core/commands/efi/efivar.c > @@ -0,0 +1,236 @@ > +/* efivar.c - Read EFI global variables. */ > +/* > + * GRUB -- GRand Unified Bootloader > + * Copyright (C) 2015 Free Software Foundation, Inc. > + * Copyright (C) 2015 CloudFlare, Inc. > + * > + * GRUB is free software: you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, either version 3 of the License, or > + * (at your option) any later version. > + * > + * GRUB is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with GRUB. If not, see . > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +GRUB_MOD_LICENSE ("GPLv3+"); > + > +static const struct grub_arg_option options[] = { > + {"format", 'f', GRUB_ARG_OPTION_OPTIONAL, N_("Parse EFI_VAR in > specific format (hex, uint8, ascii, dump). Default: hex."), > N_("FORMAT"), ARG_TYPE_STRING}, > + {"set", 's', GRUB_ARG_OPTION_OPTIONAL, N_("Save parsed result to > environment variable (does not work with dump)."), N_("ENV_VAR"), > ARG_TYPE_STRING}, > + {0, 0, 0, 0, 0, 0} > +}; > + > +enum efi_var_type > + { > + EFI_VAR_ASCII = 0, > + EFI_VAR_UINT8, > + EFI_VAR_HEX, > + EFI_VAR_DUMP, > + EFI_VAR_INVALID = -1 > + }; > + > +static enum efi_var_type > +parse_efi_var_type (const char *type) > +{ > + if (!grub_strcmp (type, "ascii")) > + return EFI_VAR_ASCII; > + > + if (!grub_strcmp (type, "uint8")) > + return EFI_VAR_UINT8; > + > + if (!grub_strcmp (type, "hex")) > + return EFI_VAR_HEX; > + > + if (!grub_strcmp (type, "dump")) > + return EFI_VAR_DUMP; > + > + return EFI_VAR_INVALID; > +} > + > +static int > +grub_print_ascii (char *str, char c) > +{ > + if (grub_iscntrl (c)) > + { > + switch (c) > + { > + case '\0': > + str[0] = '\\'; > + str[1] = '0'; > + return 2; > + > + case '\a': > + str[0] = '\\'; > + str[1] = 'a'; > + return 2; > + > + case '\b': > + str[0] = '\\'; > + str[1] = 'b'; > + return 2; > + > + case '\f': > + str[0] = '\\'; > + str[1] = 'f'; > + return 2; > + > + case '\n': > + str[0] = '\\'; > + str[1] = 'n'; > + return 2; > + > + case '\r': > + str[0] = '\\'; > + str[1] = 'r'; > + return 2; > + > + case '\t': > + str[0] = '\\'; > + str[1] = 't'; > + return 2; > + > + case '\v': > + str[0] = '\\'; > + str[1] = 'v'; > + return 2; > + > + default: > + str[0] = '.'; /* as in hexdump -C */ > + return 1; > + } > + } > + > + str[0] = c; > + return 1; > +} > + > +static grub_err_t > +grub_cmd_get_efi_var (struct grub_extcmd_context *ctxt, > + int argc, char **args) > +{ > + struct grub_arg_list *state = ctxt->state; > + grub_err_t status; > + void *efi_var = NULL; > + grub_size_t efi_var_size = 0; > + enum efi_var_type efi_type = EFI_VAR_HEX; > + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; > + char *env_var = NULL; > + grub_size_t i; > + char *ptr; > + > + if (1 != argc) > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument > expected")); > + > + if (state[0].set) > + efi_type = parse_efi_var_type (state[0].arg); > + > + if (EFI_VAR_INVALID == efi_type) > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid format > specifier")); > + > + efi_var = grub_efi_get_variable (args[0], &global, &efi_var_size); > + if (!efi_var || !efi_var_size) > + { > + status = grub_error (GRUB_ERR_READ_ERROR, N_("cannot read > variable")); > + goto err; > + } > + > + switch (efi_type) > + { > + case EFI_VAR_ASCII: > + env_var = grub_malloc (efi_var_size * 2 + 1); > + if (!env_var) > + { > + status = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of > memory")); > + goto err; > + } > + > + ptr = env_var; > + > + for (i = 0; i < efi_var_size; i++) > + ptr += grub_print_ascii (ptr, ((const char *)efi_var)[i]); > + *ptr = '\0'; > + break; > + > + case EFI_VAR_UINT8: > + env_var = grub_malloc (4); > + if (!env_var) > + { > + status = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of > memory")); > + goto err; > + } > + grub_snprintf (env_var, 4, "%u", *((grub_uint8_t *)efi_var)); > + break; > + > + case EFI_VAR_HEX: > + env_var = grub_malloc (efi_var_size * 2 + 1); > + if (!env_var) > + { > + status = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of > memory")); > + goto err; > + } > + for (i = 0; i < efi_var_size; i++) > + grub_snprintf (env_var + (i * 2), 3, "%02x", ((grub_uint8_t > *)efi_var)[i]); > + break; > + > + case EFI_VAR_DUMP: > + if (state[1].set) > + status = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot set > variable with dump format specifier")); > + else > + { > + hexdump (0, (char *)efi_var, efi_var_size); > + status = GRUB_ERR_NONE; > + } > + break; > + > + default: > + status = grub_error (GRUB_ERR_BUG, N_("should not happen (bug > in module?)")); > + goto err; > + } > + > + if (efi_type != EFI_VAR_DUMP) > + { > + if (state[1].set) > + status = grub_env_set (state[1].arg, env_var); > + else > + { > + grub_printf ("%s\n", (const char *)env_var); > + status = GRUB_ERR_NONE; > + } > + } > + > +err: > + > + grub_free (env_var); > + grub_free (efi_var); > + > + return status; > +} > + > +static grub_extcmd_t cmd = NULL; > + > +GRUB_MOD_INIT (efivar) > +{ > + cmd = grub_register_extcmd ("get_efivar", grub_cmd_get_efi_var, 0, > N_("[-f FORMAT] [-s ENV_VAR] EFI_VAR"), > + N_("Read EFI variable and print it or save its contents to > environment variable."), options); > +} > + > +GRUB_MOD_FINI (efivar) > +{ > + if (cmd) > + grub_unregister_extcmd (cmd); > +} > > > On Mon, Dec 14, 2015 at 11:08 AM, Ignat Korchagin > wrote: > >> Assuming uint8 remains - should not you check that variable size is > exactly 1 byte in this case? > > There are reports of a buggy firmware returning 4 bytes size for uint8 > > variables, however did not encounter them myself. > > > >> Do we really need unit8 at all? "hex" already provides exactly the same > functionality, not? Do you think there are cases when uint8 is really > required? > > Well, when checking for SecureBoot variable in grub configuration file > > hex mode makes it look weird and creates a point of confusion. For > > example to check if SecureBoot (suppose the result of the our command > > is stored in secure_boot env variable in hex mode) is enabled one > > should write: > > if [ secure_boot = "01" ] > > ... > > uint8 just allows to do a more straightforward config > > if [ secure_boot = 1] - this case would be false for hex mode - > > possible security breach > > ... > > > > Added goto err in the module as pointed, see patch below. I will do a > > follow-up patch for documentation once we get this confirmed. > > > > diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def > > index 0cc40bb..aa7b927 100644 > > --- a/grub-core/Makefile.core.def > > +++ b/grub-core/Makefile.core.def > > @@ -735,6 +735,12 @@ module = { > > }; > > > > module = { > > + name = efivar; > > + efi = commands/efi/efivar.c; > > + enable = efi; > > +}; > > + > > +module = { > > name = blocklist; > > common = commands/blocklist.c; > > }; > > diff --git a/grub-core/commands/efi/efivar.c > b/grub-core/commands/efi/efivar.c > > new file mode 100644 > > index 0000000..7f5a957 > > --- /dev/null > > +++ b/grub-core/commands/efi/efivar.c > > @@ -0,0 +1,251 @@ > > +/* efivar.c - Read EFI global variables. */ > > +/* > > + * GRUB -- GRand Unified Bootloader > > + * Copyright (C) 2015 Free Software Foundation, Inc. > > + * Copyright (C) 2015 CloudFlare, Inc. > > + * > > + * GRUB is free software: you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License as published by > > + * the Free Software Foundation, either version 3 of the License, or > > + * (at your option) any later version. > > + * > > + * GRUB is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > + * GNU General Public License for more details. > > + * > > + * You should have received a copy of the GNU General Public License > > + * along with GRUB. If not, see . > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +GRUB_MOD_LICENSE ("GPLv3+"); > > + > > +static const struct grub_arg_option options[] = { > > + {"format", 'f', GRUB_ARG_OPTION_OPTIONAL, N_("Parse EFI_VAR in > > specific format (hex, uint8, ascii, raw, dump). Default: hex."), > > N_("FORMAT"), ARG_TYPE_STRING}, > > + {"set", 's', GRUB_ARG_OPTION_OPTIONAL, N_("Save parsed result to > > environment variable (does not work with dump)."), N_("ENV_VAR"), > > ARG_TYPE_STRING}, > > + {0, 0, 0, 0, 0, 0} > > +}; > > + > > +enum efi_var_type > > + { > > + EFI_VAR_ASCII = 0, > > + EFI_VAR_RAW, > > + EFI_VAR_UINT8, > > + EFI_VAR_HEX, > > + EFI_VAR_DUMP, > > + EFI_VAR_INVALID = -1 > > + }; > > + > > +static enum efi_var_type > > +parse_efi_var_type (const char *type) > > +{ > > + if (!grub_strncmp (type, "ascii", sizeof("ascii"))) > > + return EFI_VAR_ASCII; > > + > > + if (!grub_strncmp (type, "raw", sizeof("raw"))) > > + return EFI_VAR_ASCII; > > + > > + if (!grub_strncmp (type, "uint8", sizeof("uint8"))) > > + return EFI_VAR_UINT8; > > + > > + if (!grub_strncmp (type, "hex", sizeof("hex"))) > > + return EFI_VAR_HEX; > > + > > + if (!grub_strncmp (type, "dump", sizeof("dump"))) > > + return EFI_VAR_DUMP; > > + > > + return EFI_VAR_INVALID; > > +} > > + > > +static int > > +grub_print_ascii (char *str, char c) > > +{ > > + if (grub_iscntrl (c)) > > + { > > + switch (c) > > + { > > + case '\0': > > + str[0] = '\\'; > > + str[1] = '0'; > > + return 2; > > + > > + case '\a': > > + str[0] = '\\'; > > + str[1] = 'a'; > > + return 2; > > + > > + case '\b': > > + str[0] = '\\'; > > + str[1] = 'b'; > > + return 2; > > + > > + case '\f': > > + str[0] = '\\'; > > + str[1] = 'f'; > > + return 2; > > + > > + case '\n': > > + str[0] = '\\'; > > + str[1] = 'n'; > > + return 2; > > + > > + case '\r': > > + str[0] = '\\'; > > + str[1] = 'r'; > > + return 2; > > + > > + case '\t': > > + str[0] = '\\'; > > + str[1] = 't'; > > + return 2; > > + > > + case '\v': > > + str[0] = '\\'; > > + str[1] = 'v'; > > + return 2; > > + > > + default: > > + str[0] = '.'; /* as in hexdump -C */ > > + return 1; > > + } > > + } > > + > > + str[0] = c; > > + return 1; > > +} > > + > > +static grub_err_t > > +grub_cmd_get_efi_var (struct grub_extcmd_context *ctxt, > > + int argc, char **args) > > +{ > > + struct grub_arg_list *state = ctxt->state; > > + grub_err_t status; > > + void *efi_var = NULL; > > + grub_size_t efi_var_size = 0; > > + enum efi_var_type efi_type = EFI_VAR_HEX; > > + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; > > + char *env_var = NULL; > > + grub_size_t i; > > + char *ptr; > > + > > + if (1 != argc) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument > expected")); > > + > > + if (state[0].set) > > + efi_type = parse_efi_var_type (state[0].arg); > > + > > + if (EFI_VAR_INVALID == efi_type) > > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid format > specifier")); > > + > > + efi_var = grub_efi_get_variable (args[0], &global, &efi_var_size); > > + if (!efi_var || !efi_var_size) > > + { > > + status = grub_error (GRUB_ERR_READ_ERROR, N_("cannot read > variable")); > > + goto err; > > + } > > + > > + switch (efi_type) > > + { > > + case EFI_VAR_ASCII: > > + env_var = grub_malloc (efi_var_size * 2 + 1); > > + if (!env_var) > > + { > > + status = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of > memory")); > > + goto err; > > + } > > + > > + ptr = env_var; > > + > > + for (i = 0; i < efi_var_size; i++) > > + ptr += grub_print_ascii (ptr, ((const char *)efi_var)[i]); > > + *ptr = '\0'; > > + break; > > + > > + case EFI_VAR_RAW: > > + env_var = grub_malloc (efi_var_size + 1); > > + if (!env_var) > > + { > > + status = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of > memory")); > > + goto err; > > + } > > + grub_memcpy (env_var, efi_var, efi_var_size); > > + env_var[efi_var_size] = '\0'; > > + break; > > + > > + case EFI_VAR_UINT8: > > + env_var = grub_malloc (4); > > + if (!env_var) > > + { > > + status = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of > memory")); > > + goto err; > > + } > > + grub_snprintf (env_var, 4, "%u", *((grub_uint8_t *)efi_var)); > > + break; > > + > > + case EFI_VAR_HEX: > > + env_var = grub_malloc (efi_var_size * 2 + 1); > > + if (!env_var) > > + { > > + status = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of > memory")); > > + goto err; > > + } > > + for (i = 0; i < efi_var_size; i++) > > + grub_snprintf (env_var + (i * 2), 3, "%02x", ((grub_uint8_t > > *)efi_var)[i]); > > + break; > > + > > + case EFI_VAR_DUMP: > > + if (state[1].set) > > + status = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot set > > variable with dump format specifier")); > > + else > > + { > > + hexdump (0, (char *)efi_var, efi_var_size); > > + status = GRUB_ERR_NONE; > > + } > > + break; > > + > > + default: > > + status = grub_error (GRUB_ERR_BUG, N_("should not happen (bug > > in module?)")); > > + goto err; > > + } > > + > > + if (efi_type != EFI_VAR_DUMP) > > + { > > + if (state[1].set) > > + status = grub_env_set (state[1].arg, env_var); > > + else > > + { > > + grub_printf ("%s\n", (const char *)env_var); > > + status = GRUB_ERR_NONE; > > + } > > + } > > + > > +err: > > + > > + grub_free (env_var); > > + grub_free (efi_var); > > + > > + return status; > > +} > > + > > +static grub_extcmd_t cmd = NULL; > > + > > +GRUB_MOD_INIT (efivar) > > +{ > > + cmd = grub_register_extcmd ("get_efivar", grub_cmd_get_efi_var, 0, > > N_("[-f FORMAT] [-s ENV_VAR] EFI_VAR"), > > + N_("Read EFI variable and print it or save its contents to > > environment variable."), options); > > +} > > + > > +GRUB_MOD_FINI (efivar) > > +{ > > + if (cmd) > > + grub_unregister_extcmd (cmd); > > +} > --001a114f098c988bba052a7b7c7d Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
Hi. Are we still considering this?

On Mon, Dec 14, 2015 at 11:17 AM, Ignat K= orchagin <ignat@cloudflare.com> wrote:
Sorry, pasted wrong file. Here is the correct one:

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 0cc40bb..aa7b927 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -735,6 +735,12 @@ module =3D {
=C2=A0};

=C2=A0module =3D {
+=C2=A0 name =3D efivar;
+=C2=A0 efi =3D commands/efi/efivar.c;
+=C2=A0 enable =3D efi;
+};
+
+module =3D {
=C2=A0 =C2=A0name =3D blocklist;
=C2=A0 =C2=A0common =3D commands/blocklist.c;
=C2=A0};
diff --git a/grub-core/commands/efi/efivar.c b/grub-core/commands/efi/efiva= r.c
new file mode 100644
index 0000000..7fe7bda
--- /dev/null
+++ b/grub-core/commands/efi/efivar.c
@@ -0,0 +1,236 @@
+/* efivar.c - Read EFI global variables. */
+/*
+ *=C2=A0 GRUB=C2=A0 --=C2=A0 GRand Unified Bootloader
+ *=C2=A0 Copyright (C) 2015 Free Software Foundation, Inc.
+ *=C2=A0 Copyright (C) 2015 CloudFlare, Inc.
+ *
+ *=C2=A0 GRUB is free software: you can redistribute it and/or modify
+ *=C2=A0 it under the terms of the GNU General Public License as published= by
+ *=C2=A0 the Free Software Foundation, either version 3 of the License, or=
+ *=C2=A0 (at your option) any later version.
+ *
+ *=C2=A0 GRUB is distributed in the hope that it will be useful,
+ *=C2=A0 but WITHOUT ANY WARRANTY; without even the implied warranty of + *=C2=A0 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 See th= e
+ *=C2=A0 GNU General Public License for more details.
+ *
+ *=C2=A0 You should have received a copy of the GNU General Public License=
+ *=C2=A0 along with GRUB.=C2=A0 If not, see <http://www.gnu.org/lice= nses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/extcmd.h>
+#include <grub/env.h>
+#include <grub/lib/hexdump.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =3D {
+=C2=A0 {"format", 'f', GRUB_ARG_OPTION_OPTIONAL, N_(&quo= t;Parse EFI_VAR in
specific format (hex, uint8, ascii, dump). Default: hex.")= ,
N_("FORMAT"), ARG_TYPE_STRING},
+=C2=A0 {"set", 's', GRUB_ARG_OPTION_OPTIONAL, N_("S= ave parsed result to
environment variable (does not work with dump)."), N_("ENV_VAR&qu= ot;),
ARG_TYPE_STRING},
+=C2=A0 {0, 0, 0, 0, 0, 0}
+};
+
+enum efi_var_type
+=C2=A0 {
+=C2=A0 =C2=A0 EFI_VAR_ASCII =3D 0,
+=C2=A0 =C2=A0 EFI_VAR_UINT8,
+=C2=A0 =C2=A0 EFI_VAR_HEX,
+=C2=A0 =C2=A0 EFI_VAR_DUMP,
+=C2=A0 =C2=A0 EFI_VAR_INVALID =3D -1
+=C2=A0 };
+
+static enum efi_var_type
+parse_efi_var_type (const char *type)
+{
+=C2=A0 if (!grub_strcmp (type, "ascii"))
+=C2=A0 =C2=A0 return EFI_VAR_ASCII;
+
+=C2=A0 if (!grub_strcmp (type, "uint8"))
+=C2=A0 =C2=A0 return EFI_VAR_UINT8;
+
+=C2=A0 if (!grub_strcmp (type, "hex"))
+=C2=A0 =C2=A0 return EFI_VAR_HEX;
+
+=C2=A0 if (!grub_strcmp (type, "dump"))
+=C2=A0 =C2=A0 return EFI_VAR_DUMP;=
+
+=C2=A0 return EFI_VAR_INVALID;
+}
+
+static int
+grub_print_ascii (char *str, char c)
+{
+=C2=A0 if (grub_iscntrl (c))
+=C2=A0 {
+=C2=A0 =C2=A0 switch (c)
+=C2=A0 =C2=A0 =C2=A0 {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\0':
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D '0';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\a':
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'a';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\b':
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'b';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\f':
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'f';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\n':
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'n';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\r':
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'r';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\t':
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 't';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\v':
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'v';
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
+
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 default:
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '.'; /* as in hexdum= p -C */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 1;
+=C2=A0 =C2=A0 =C2=A0 }
+=C2=A0 }
+
+=C2=A0 str[0] =3D c;
+=C2=A0 return 1;
+}
+
+static grub_err_t
+grub_cmd_get_efi_var (struct grub_extcmd_context *ctxt,
+=C2=A0 int argc, char **args)
+{
+=C2=A0 struct grub_arg_list *state =3D ctxt->state;
+=C2=A0 grub_err_t status;
+=C2=A0 void *efi_var =3D NULL;
+=C2=A0 grub_size_t efi_var_size =3D 0;
+=C2=A0 enum efi_var_type efi_type =3D EFI_VAR_HEX;
+=C2=A0 grub_efi_guid_t global =3D GRUB_EFI_GLOBAL_VARIABLE_GUID;
+=C2=A0 char *env_var =3D NULL;
+=C2=A0 grub_size_t i;
+=C2=A0 char *ptr;
+
+=C2=A0 if (1 !=3D argc)
+=C2=A0 =C2=A0 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argum= ent expected"));
+
+=C2=A0 if (state[0].set)
+=C2=A0 =C2=A0 efi_type =3D parse_efi_var_type (state[0].arg);
+
+=C2=A0 if (EFI_VAR_INVALID =3D=3D efi_type)
+=C2=A0 =C2=A0 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid f= ormat specifier"));
+
+=C2=A0 efi_var =3D grub_efi_get_variable (args[0], &global, &efi_v= ar_size);
+=C2=A0 if (!efi_var || !efi_var_size)
+=C2=A0 =C2=A0 {
+=C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_READ_ERROR, N_("= cannot read variable"));
+=C2=A0 =C2=A0 =C2=A0 goto err;
+=C2=A0 =C2=A0 }
+
+=C2=A0 switch (efi_type)
+=C2=A0 {
+=C2=A0 =C2=A0 case EFI_VAR_ASCII:
+=C2=A0 =C2=A0 =C2=A0 env_var =3D grub_malloc (efi_var_size * 2 + 1);
+=C2=A0 =C2=A0 =C2=A0 if (!env_var)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_OUT_OF_= MEMORY, N_("out of memory"));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto err;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
+
+=C2=A0 =C2=A0 =C2=A0 ptr =3D env_var;
+
+=C2=A0 =C2=A0 =C2=A0 for (i =3D 0; i < efi_var_size; i++)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 ptr +=3D grub_print_ascii (ptr, ((const char *= )efi_var)[i]);
+=C2=A0 =C2=A0 =C2=A0 *ptr =3D '\0';
+=C2=A0 =C2=A0 =C2=A0 break;
+
+=C2=A0 =C2=A0 case EFI= _VAR_UINT8:
+=C2=A0 =C2=A0 =C2=A0 env_var =3D grub_malloc (4);
+=C2=A0 =C2=A0 =C2=A0 if (!env_var)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_OUT_OF_= MEMORY, N_("out of memory"));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto err;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 =C2=A0 grub_snprintf (env_var, 4, "%u", *((grub_ui= nt8_t *)efi_var));
+=C2=A0 =C2=A0 =C2=A0 break;
+
+=C2=A0 =C2=A0 case EFI_VAR_HEX:
+=C2=A0 =C2=A0 =C2=A0 env_var =3D grub_malloc (efi_var_size * 2 + 1);
+=C2=A0 =C2=A0 =C2=A0 if (!env_var)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_OUT_OF_= MEMORY, N_("out of memory"));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto err;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 =C2=A0 for (i =3D 0; i < efi_var_size; i++)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 grub_snprintf (env_var + (i * 2), 3, "%02= x", ((grub_uint8_t
*)efi_var)[i]);
+=C2=A0 =C2=A0 =C2=A0 break;
+
+=C2=A0 =C2=A0 case EFI_VAR_DUMP:
+=C2=A0 =C2=A0 =C2=A0 if (state[1].set)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_BAD_ARGUMENT, = N_("cannot set
variable with dump format specifier"));
+=C2=A0 =C2=A0 =C2=A0 else
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 hexdump (0, (char *)efi_var, efi_var_si= ze);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D GRUB_ERR_NONE;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 =C2=A0 break;
+
+=C2=A0 =C2=A0 default:
+=C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_BUG, N_("should = not happen (bug
in module?)"));
+=C2=A0 =C2=A0 =C2=A0 goto err;
+=C2=A0 }
+
+=C2=A0 if (efi_type !=3D EFI_VAR_DUMP)
+=C2=A0 =C2=A0 {
+=C2=A0 =C2=A0 =C2=A0 if (state[1].set)
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_env_set (state[1].arg, env_var= );
+=C2=A0 =C2=A0 =C2=A0 else
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 grub_printf ("%s\n", (const c= har *)env_var);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D GRUB_ERR_NONE;
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 }
+
+err:
+
+=C2=A0 grub_free (env_var);
+=C2=A0 grub_free (efi_var);
+
+=C2=A0 return status;
+}
+
+static grub_extcmd_t cmd =3D NULL;
+
+GRUB_MOD_INIT (efivar)
+{
+=C2=A0 cmd =3D grub_register_extcmd ("get_efivar", grub_cmd_get_= efi_var, 0,
N_("[-f FORMAT] [-s ENV_VAR] EFI_VAR"),
+ N_("Read EFI variable and print it or save its contents to
environment variable."), options);
+}
+
+GRUB_MOD_FINI (efivar)
+{
+=C2=A0 if (cmd)
+=C2=A0 =C2=A0 grub_unregister_extcmd (cmd);
+}


On Mon, Dec 14, 2015 at= 11:08 AM, Ignat Korchagin <igna= t@cloudflare.com> wrote:
>> Assuming uint8 remains - should not you check that variable size i= s exactly 1 byte in this case?
> There are reports of a buggy firmware returning 4 bytes size for uint8=
> variables, however did not encounter them myself.
>
>> Do we really need unit8 at all? "hex" already provides e= xactly the same functionality, not? Do you think there are cases when uint8= is really required?
> Well, when checking for SecureBoot variable in grub configuration file=
> hex mode makes it look weird and creates a point of confusion. For
> example to check if SecureBoot (suppose the result of the our command<= br> > is stored in secure_boot env variable in hex mode) is enabled one
> should write:
> if [ secure_boot =3D "01" ]
> ...
> uint8 just allows to do a more straightforward config
> if [ secure_boot =3D 1] - this case would be false for hex mode -
> possible security breach
> ...
>
> Added goto err in the module as pointed, see patch below. I will do a<= br> > follow-up patch for documentation once we get this confirmed.
>
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def=
> index 0cc40bb..aa7b927 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -735,6 +735,12 @@ module =3D {
>=C2=A0 };
>
>=C2=A0 module =3D {
> +=C2=A0 name =3D efivar;
> +=C2=A0 efi =3D commands/efi/efivar.c;
> +=C2=A0 enable =3D efi;
> +};
> +
> +module =3D {
>=C2=A0 =C2=A0 name =3D blocklist;
>=C2=A0 =C2=A0 common =3D commands/blocklist.c;
>=C2=A0 };
> diff --git a/grub-core/commands/efi/efivar.c b/grub-core/commands/efi/= efivar.c
> new file mode 100644
> index 0000000..7f5a957
> --- /dev/null
> +++ b/grub-core/commands/efi/efivar.c
> @@ -0,0 +1,251 @@
> +/* efivar.c - Read EFI global variables. */
> +/*
> + *=C2=A0 GRUB=C2=A0 --=C2=A0 GRand Unified Bootloader
> + *=C2=A0 Copyright (C) 2015 Free Software Foundation, Inc.
> + *=C2=A0 Copyright (C) 2015 CloudFlare, Inc.
> + *
> + *=C2=A0 GRUB is free software: you can redistribute it and/or modify=
> + *=C2=A0 it under the terms of the GNU General Public License as publ= ished by
> + *=C2=A0 the Free Software Foundation, either version 3 of the Licens= e, or
> + *=C2=A0 (at your option) any later version.
> + *
> + *=C2=A0 GRUB is distributed in the hope that it will be useful,
> + *=C2=A0 but WITHOUT ANY WARRANTY; without even the implied warranty = of
> + *=C2=A0 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 S= ee the
> + *=C2=A0 GNU General Public License for more details.
> + *
> + *=C2=A0 You should have received a copy of the GNU General Public Li= cense
> + *=C2=A0 along with GRUB.=C2=A0 If not, see <http://www.gnu.org= /licenses/>.
> + */
> +
> +#include <grub/types.h>
> +#include <grub/mm.h>
> +#include <grub/misc.h>
> +#include <grub/efi/api.h>
> +#include <grub/efi/efi.h>
> +#include <grub/extcmd.h>
> +#include <grub/env.h>
> +#include <grub/lib/hexdump.h>
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +static const struct grub_arg_option options[] =3D {
> +=C2=A0 {"format", 'f', GRUB_ARG_OPTION_OPTIONAL, N_= ("Parse EFI_VAR in
> specific format (hex, uint8, ascii, raw, dump). Default: hex."),<= br> > N_("FORMAT"), ARG_TYPE_STRING},
> +=C2=A0 {"set", 's', GRUB_ARG_OPTION_OPTIONAL, N_(&q= uot;Save parsed result to
> environment variable (does not work with dump)."), N_("ENV_V= AR"),
> ARG_TYPE_STRING},
> +=C2=A0 {0, 0, 0, 0, 0, 0}
> +};
> +
> +enum efi_var_type
> +=C2=A0 {
> +=C2=A0 =C2=A0 EFI_VAR_ASCII =3D 0,
> +=C2=A0 =C2=A0 EFI_VAR_RAW,
> +=C2=A0 =C2=A0 EFI_VAR_UINT8,
> +=C2=A0 =C2=A0 EFI_VAR_HEX,
> +=C2=A0 =C2=A0 EFI_VAR_DUMP,
> +=C2=A0 =C2=A0 EFI_VAR_INVALID =3D -1
> +=C2=A0 };
> +
> +static enum efi_var_type
> +parse_efi_var_type (const char *type)
> +{
> +=C2=A0 if (!grub_strncmp (type, "ascii", sizeof("ascii= ")))
> +=C2=A0 =C2=A0 return EFI_VAR_ASCII;
> +
> +=C2=A0 if (!grub_strncmp (type, "raw", sizeof("raw&quo= t;)))
> +=C2=A0 =C2=A0 return EFI_VAR_ASCII;
> +
> +=C2=A0 if (!grub_strncmp (type, "uint8", sizeof("uint8= ")))
> +=C2=A0 =C2=A0 return EFI_VAR_UINT8;
> +
> +=C2=A0 if (!grub_strncmp (type, "hex", sizeof("hex&quo= t;)))
> +=C2=A0 =C2=A0 return EFI_VAR_HEX;
> +
> +=C2=A0 if (!grub_strncmp (type, "dump", sizeof("dump&q= uot;)))
> +=C2=A0 =C2=A0 return EFI_VAR_DUMP;
> +
> +=C2=A0 return EFI_VAR_INVALID;
> +}
> +
> +static int
> +grub_print_ascii (char *str, char c)
> +{
> +=C2=A0 if (grub_iscntrl (c))
> +=C2=A0 {
> +=C2=A0 =C2=A0 switch (c)
> +=C2=A0 =C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\0':
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D '0';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\a':
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'a';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\b':
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'b';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\f':
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'f';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\n':
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'n';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\r':
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'r';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\t':
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 't';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 case '\v':
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '\\';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[1] =3D 'v';
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 2;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 default:
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str[0] =3D '.'; /* as in h= exdump -C */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 1;
> +=C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 }
> +
> +=C2=A0 str[0] =3D c;
> +=C2=A0 return 1;
> +}
> +
> +static grub_err_t
> +grub_cmd_get_efi_var (struct grub_extcmd_context *ctxt,
> +=C2=A0 int argc, char **args)
> +{
> +=C2=A0 struct grub_arg_list *state =3D ctxt->state;
> +=C2=A0 grub_err_t status;
> +=C2=A0 void *efi_var =3D NULL;
> +=C2=A0 grub_size_t efi_var_size =3D 0;
> +=C2=A0 enum efi_var_type efi_type =3D EFI_VAR_HEX;
> +=C2=A0 grub_efi_guid_t global =3D GRUB_EFI_GLOBAL_VARIABLE_GUID;
> +=C2=A0 char *env_var =3D NULL;
> +=C2=A0 grub_size_t i;
> +=C2=A0 char *ptr;
> +
> +=C2=A0 if (1 !=3D argc)
> +=C2=A0 =C2=A0 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one = argument expected"));
> +
> +=C2=A0 if (state[0].set)
> +=C2=A0 =C2=A0 efi_type =3D parse_efi_var_type (state[0].arg);
> +
> +=C2=A0 if (EFI_VAR_INVALID =3D=3D efi_type)
> +=C2=A0 =C2=A0 return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("inva= lid format specifier"));
> +
> +=C2=A0 efi_var =3D grub_efi_get_variable (args[0], &global, &= efi_var_size);
> +=C2=A0 if (!efi_var || !efi_var_size)
> +=C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_READ_ERROR, N_(&= quot;cannot read variable"));
> +=C2=A0 =C2=A0 =C2=A0 goto err;
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 switch (efi_type)
> +=C2=A0 {
> +=C2=A0 =C2=A0 case EFI_VAR_ASCII:
> +=C2=A0 =C2=A0 =C2=A0 env_var =3D grub_malloc (efi_var_size * 2 + 1);<= br> > +=C2=A0 =C2=A0 =C2=A0 if (!env_var)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_OU= T_OF_MEMORY, N_("out of memory"));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto err;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 =C2=A0 ptr =3D env_var;
> +
> +=C2=A0 =C2=A0 =C2=A0 for (i =3D 0; i < efi_var_size; i++)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 ptr +=3D grub_print_ascii (ptr, ((const c= har *)efi_var)[i]);
> +=C2=A0 =C2=A0 =C2=A0 *ptr =3D '\0';
> +=C2=A0 =C2=A0 =C2=A0 break;
> +
> +=C2=A0 =C2=A0 case EFI_VAR_RAW:
> +=C2=A0 =C2=A0 =C2=A0 env_var =3D grub_malloc (efi_var_size + 1);
> +=C2=A0 =C2=A0 =C2=A0 if (!env_var)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_OU= T_OF_MEMORY, N_("out of memory"));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto err;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 =C2=A0 grub_memcpy (env_var, efi_var, efi_var_size); > +=C2=A0 =C2=A0 =C2=A0 env_var[efi_var_size] =3D '\0';
> +=C2=A0 =C2=A0 =C2=A0 break;
> +
> +=C2=A0 =C2=A0 case EFI_VAR_UINT8:
> +=C2=A0 =C2=A0 =C2=A0 env_var =3D grub_malloc (4);
> +=C2=A0 =C2=A0 =C2=A0 if (!env_var)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_OU= T_OF_MEMORY, N_("out of memory"));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto err;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 =C2=A0 grub_snprintf (env_var, 4, "%u", *((gr= ub_uint8_t *)efi_var));
> +=C2=A0 =C2=A0 =C2=A0 break;
> +
> +=C2=A0 =C2=A0 case EFI_VAR_HEX:
> +=C2=A0 =C2=A0 =C2=A0 env_var =3D grub_malloc (efi_var_size * 2 + 1);<= br> > +=C2=A0 =C2=A0 =C2=A0 if (!env_var)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_OU= T_OF_MEMORY, N_("out of memory"));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto err;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 =C2=A0 for (i =3D 0; i < efi_var_size; i++)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 grub_snprintf (env_var + (i * 2), 3, &quo= t;%02x", ((grub_uint8_t
> *)efi_var)[i]);
> +=C2=A0 =C2=A0 =C2=A0 break;
> +
> +=C2=A0 =C2=A0 case EFI_VAR_DUMP:
> +=C2=A0 =C2=A0 =C2=A0 if (state[1].set)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_BAD_ARGUM= ENT, N_("cannot set
> variable with dump format specifier"));
> +=C2=A0 =C2=A0 =C2=A0 else
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 hexdump (0, (char *)efi_var, efi_v= ar_size);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D GRUB_ERR_NONE;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 =C2=A0 break;
> +
> +=C2=A0 =C2=A0 default:
> +=C2=A0 =C2=A0 =C2=A0 status =3D grub_error (GRUB_ERR_BUG, N_("sh= ould not happen (bug
> in module?)"));
> +=C2=A0 =C2=A0 =C2=A0 goto err;
> +=C2=A0 }
> +
> +=C2=A0 if (efi_type !=3D EFI_VAR_DUMP)
> +=C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 if (state[1].set)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D grub_env_set (state[1].arg, en= v_var);
> +=C2=A0 =C2=A0 =C2=A0 else
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 grub_printf ("%s\n", (co= nst char *)env_var);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 status =3D GRUB_ERR_NONE;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 }
> +
> +err:
> +
> +=C2=A0 grub_free (env_var);
> +=C2=A0 grub_free (efi_var);
> +
> +=C2=A0 return status;
> +}
> +
> +static grub_extcmd_t cmd =3D NULL;
> +
> +GRUB_MOD_INIT (efivar)
> +{
> +=C2=A0 cmd =3D grub_register_extcmd ("get_efivar", grub_cmd= _get_efi_var, 0,
> N_("[-f FORMAT] [-s ENV_VAR] EFI_VAR"),
> + N_("Read EFI variable and print it or save its contents to
> environment variable."), options);
> +}
> +
> +GRUB_MOD_FINI (efivar)
> +{
> +=C2=A0 if (cmd)
> +=C2=A0 =C2=A0 grub_unregister_extcmd (cmd);
> +}

--001a114f098c988bba052a7b7c7d--