From 73746f036743f21144a9f88af264d162c9cfd624 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 7 Jan 2016 15:31:36 -0800 Subject: [PATCH 1/4] Fix hex representation of binary variable contents The getenv code was mishandling the conversion of binary to hex. Grub's sprintf() doesn't seem to support the full set of format conversions, so fix this in the nasty way. --- grub-core/commands/efi/getenv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/commands/efi/getenv.c b/grub-core/commands/efi/getenv.c index 5a829f5e4..7eb2c4506 100644 --- a/grub-core/commands/efi/getenv.c +++ b/grub-core/commands/efi/getenv.c @@ -119,7 +119,7 @@ grub_cmd_getenv (grub_extcmd_context_t ctxt, int argc, char **args) { bindata = grub_zalloc(datasize * 2 + 1); for (i=0; i Date: Thu, 7 Jan 2016 15:33:36 -0800 Subject: [PATCH 2/4] Allow passing of trusted keys via variables Add support for adding gpg keys to the trusted database with a new command called "trust_var". This takes the contents of a variable (in ascii-encoded hex) and interprets it as a gpg public key. --- grub-core/commands/verify.c | 94 ++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/grub-core/commands/verify.c b/grub-core/commands/verify.c index 9620a3b4c..24fac298f 100644 --- a/grub-core/commands/verify.c +++ b/grub-core/commands/verify.c @@ -52,6 +52,20 @@ static const struct grub_arg_option options[] = {0, 0, 0, 0, 0, 0} }; +static grub_ssize_t +pseudo_read (struct grub_file *file, char *buf, grub_size_t len) +{ + grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len); + return len; +} + +/* Filesystem descriptor. */ +struct grub_fs pseudo_fs = + { + .name = "pseudo", + .read = pseudo_read +}; + static grub_err_t read_packet_header (grub_file_t sig, grub_uint8_t *out_type, grub_size_t *len) { @@ -694,6 +708,64 @@ grub_cmd_trust (grub_extcmd_context_t ctxt, return GRUB_ERR_NONE; } +static grub_err_t +grub_cmd_trust_var (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_file pseudo_file; + const char *var; + char *data; + struct grub_public_key *pk = NULL; + unsigned int i, idx0, idx1; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + + var = grub_env_get (args[0]); + if (!var) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unknown variable")); + + data = grub_zalloc (grub_strlen (var) / 2); + if (!data) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate memory for key")); + + /* For the want of sscanf() */ + for (i = 0; i < grub_strlen (var); i += 2) + { + if (var[i] < 0x40) + idx0 = var[i] - 0x30; + else + idx0 = var[i] - 0x57; + + if (var[i+1] < 0x40) + idx1 = var[i+1] - 0x30; + else + idx1 = var[i+1] - 0x57; + + data[i/2] = ((idx0 << 4) & 0xf0) | (idx1 & 0x0f); + } + + grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); + + pseudo_file.fs = &pseudo_fs; + pseudo_file.size = grub_strlen (var) / 2; + pseudo_file.data = data; + + pk = grub_load_public_key (&pseudo_file); + if (!pk) + { + grub_free(data); + return grub_errno; + } + + pk->next = grub_pk_trusted; + grub_pk_trusted = pk; + + grub_free(data); + return GRUB_ERR_NONE; + +} + static grub_err_t grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), @@ -948,24 +1020,8 @@ grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)), return grub_strdup (sec ? "enforce" : "no"); } -static grub_ssize_t -pseudo_read (struct grub_file *file, char *buf, grub_size_t len) -{ - grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len); - return len; -} - - -/* Filesystem descriptor. */ -struct grub_fs pseudo_fs = - { - .name = "pseudo", - .read = pseudo_read -}; - - static grub_extcmd_t cmd, cmd_trust; -static grub_command_t cmd_distrust, cmd_list; +static grub_command_t cmd_trust_var, cmd_distrust, cmd_list; GRUB_MOD_INIT(verify) { @@ -1018,6 +1074,9 @@ GRUB_MOD_INIT(verify) N_("[-s|--skip-sig] PUBKEY_FILE"), N_("Add PUBKEY_FILE to trusted keys."), options); + cmd_trust_var = grub_register_command ("trust_var", grub_cmd_trust_var, + N_("PUBKEY_VAR"), + N_("Add the contents of PUBKEY_VAR to trusted keys.")); cmd_list = grub_register_command ("list_trusted", grub_cmd_list, 0, N_("Show the list of trusted keys.")); @@ -1031,6 +1090,7 @@ GRUB_MOD_FINI(verify) grub_file_filter_unregister (GRUB_FILE_FILTER_PUBKEY); grub_unregister_extcmd (cmd); grub_unregister_extcmd (cmd_trust); + grub_unregister_command (cmd_trust_var); grub_unregister_command (cmd_list); grub_unregister_command (cmd_distrust); } From 78db6bcf3380c43e7290580d4044a6ae28531c84 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 7 Jan 2016 17:27:15 -0800 Subject: [PATCH 3/4] Allow non-default ports for HTTP requests Add support for passing ports in HTTP requests. This takes the form of: (http,serverip:portnum)/file --- grub-core/net/http.c | 8 ++++++-- grub-core/net/net.c | 10 +++++++++- include/grub/net.h | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/grub-core/net/http.c b/grub-core/net/http.c index 4684f8b33..0dbb49a5e 100644 --- a/grub-core/net/http.c +++ b/grub-core/net/http.c @@ -309,7 +309,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) { http_data_t data = file->data; grub_uint8_t *ptr; - int i; + int i, port; struct grub_net_buff *nb; grub_err_t err; @@ -391,8 +391,12 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) grub_netbuff_put (nb, 2); grub_memcpy (ptr, "\r\n", 2); + if (file->device->net->port) + port = file->device->net->port; + else + port = HTTP_PORT; data->sock = grub_net_tcp_open (file->device->net->server, - HTTP_PORT, http_receive, + port, http_receive, http_err, http_err, file); if (!data->sock) diff --git a/grub-core/net/net.c b/grub-core/net/net.c index a0472d5d4..ea1ff7d01 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -1273,7 +1273,7 @@ grub_net_open_real (const char *name) grub_net_app_level_t proto; const char *protname, *server; grub_size_t protnamelen; - int try; + int try, port = 0; if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) { @@ -1290,7 +1290,14 @@ grub_net_open_real (const char *name) else { const char *comma; + char *colon; comma = grub_strchr (name, ','); + colon = grub_strchr (name, ':'); + if (colon) + { + port = (int) grub_strtol(colon+1, NULL, 10); + *colon = '\0'; + } if (comma) { protnamelen = comma - name; @@ -1325,6 +1332,7 @@ grub_net_open_real (const char *name) if (server) { ret->server = grub_strdup (server); + ret->port = port; if (!ret->server) { grub_free (ret); diff --git a/include/grub/net.h b/include/grub/net.h index 538baa33e..bb5e9c7c9 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -264,6 +264,7 @@ typedef struct grub_net grub_fs_t fs; int eof; int stall; + int port; } *grub_net_t; extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name); From 4d5d7be005bb5c15c07472461b528dea65a58cc6 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 7 Jan 2016 22:55:13 -0800 Subject: [PATCH 4/4] Send a user class identifier in bootp requests It's helpful to determine that a request was sent by grub in order to permit the server to provide different information at different stages of the boot process. Send GRUB2 as a type 77 DHCP option when sending bootp packets in order to make this possible. --- grub-core/net/bootp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index 4fdeac3ef..8519847eb 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -25,6 +25,11 @@ #include #include +static grub_uint8_t grub_userclass[] = {GRUB_NET_BOOTP_RFC1048_MAGIC_0, + GRUB_NET_BOOTP_RFC1048_MAGIC_1, + GRUB_NET_BOOTP_RFC1048_MAGIC_2, + GRUB_NET_BOOTP_RFC1048_MAGIC_3, + 0x4D, 0x05, 'G', 'R', 'U', 'B', '2'}; static void parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask) { @@ -525,6 +530,7 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), pack->seconds = grub_cpu_to_be16 (t); grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6); + grub_memcpy (&pack->vendor, grub_userclass, sizeof(grub_userclass)); grub_netbuff_push (nb, sizeof (*udph));