]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
* grub-core/commands/loadenv.c: Support skipping signature check
authorJon McCune <jonmccune@google.com>
Fri, 27 Sep 2013 00:08:32 +0000 (02:08 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 27 Sep 2013 00:08:32 +0000 (02:08 +0200)
and variable names filtering.

ChangeLog
grub-core/commands/loadenv.c
grub-core/lib/envblk.c
include/grub/lib/envblk.h
util/grub-editenv.c

index ae1c0ba4766c09792a65689cc5568d8b1e6f7748..f1a6ac2771206b5594c4545e8b2e9763a65b5c2a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-09-24  Jon McCune <jonmccune@google.com>
+
+       * grub-core/commands/loadenv.c: Support skipping signature check
+       and variable names filtering.
+
 2013-09-24  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/kern/emu/hostdisk_unix.c: Declare AROS as non-unix.
index c0a42c54211d8b18730b89a530f94d40ee34a7fc..64c2b7ecf398d6c0010d9224ab0c290ac1dc4881 100644 (file)
@@ -35,45 +35,53 @@ static const struct grub_arg_option options[] =
     /* TRANSLATORS: This option is used to override default filename
        for loading and storing environment.  */
     {"file", 'f', 0, N_("Specify filename."), 0, ARG_TYPE_PATHNAME},
+    {"skip-sig", 's', 0,
+     N_("Skip signature-checking of the environment file."), 0, ARG_TYPE_NONE},
     {0, 0, 0, 0, 0, 0}
   };
 
+/* Opens 'filename' with compression filters disabled. Optionally disables the
+   PUBKEY filter (that insists upon properly signed files) as well.  PUBKEY
+   filter is restored before the function returns. */
 static grub_file_t
-open_envblk_file (char *filename)
+open_envblk_file (char *filename, int untrusted)
 {
   grub_file_t file;
+  char *buf = 0;
 
   if (! filename)
     {
       const char *prefix;
+      int len;
 
       prefix = grub_env_get ("prefix");
-      if (prefix)
-        {
-          int len;
-
-          len = grub_strlen (prefix);
-          filename = grub_malloc (len + 1 + sizeof (GRUB_ENVBLK_DEFCFG));
-          if (! filename)
-            return 0;
-
-          grub_strcpy (filename, prefix);
-          filename[len] = '/';
-          grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG);
-         grub_file_filter_disable_compression ();
-          file = grub_file_open (filename);
-          grub_free (filename);
-          return file;
-        }
-      else
+      if (! prefix)
         {
           grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
           return 0;
         }
+
+      len = grub_strlen (prefix);
+      buf = grub_malloc (len + 1 + sizeof (GRUB_ENVBLK_DEFCFG));
+      if (! buf)
+        return 0;
+      filename = buf;
+
+      grub_strcpy (filename, prefix);
+      filename[len] = '/';
+      grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG);
     }
 
+  /* The filters that are disabled will be re-enabled by the call to
+     grub_file_open() after this particular file is opened. */
   grub_file_filter_disable_compression ();
-  return grub_file_open (filename);
+  if (untrusted)
+    grub_file_filter_disable_pubkey ();
+
+  file = grub_file_open (filename);
+
+  grub_free (buf);
+  return file;
 }
 
 static grub_envblk_t
@@ -114,24 +122,56 @@ read_envblk_file (grub_file_t file)
   return envblk;
 }
 
+struct grub_env_whitelist
+{
+  grub_size_t len;
+  char **list;
+};
+typedef struct grub_env_whitelist grub_env_whitelist_t;
+
+static int
+test_whitelist_membership (const char* name,
+                           const grub_env_whitelist_t* whitelist)
+{
+  grub_size_t i;
+
+  for (i = 0; i < whitelist->len; i++)
+    if (grub_strcmp (name, whitelist->list[i]) == 0)
+      return 1;  /* found it */
+
+  return 0;  /* not found */
+}
+
 /* Helper for grub_cmd_load_env.  */
 static int
-set_var (const char *name, const char *value)
+set_var (const char *name, const char *value, void *whitelist)
 {
-  grub_env_set (name, value);
+  if (! whitelist)
+    {
+      grub_env_set (name, value);
+      return 0;
+    }
+
+  if (test_whitelist_membership (name,
+                                (const grub_env_whitelist_t *) whitelist))
+    grub_env_set (name, value);
+
   return 0;
 }
 
 static grub_err_t
-grub_cmd_load_env (grub_extcmd_context_t ctxt,
-                  int argc __attribute__ ((unused)),
-                  char **args __attribute__ ((unused)))
+grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args)
 {
   struct grub_arg_list *state = ctxt->state;
   grub_file_t file;
   grub_envblk_t envblk;
+  grub_env_whitelist_t whitelist;
+
+  whitelist.len = argc;
+  whitelist.list = args;
 
-  file = open_envblk_file ((state[0].set) ? state[0].arg : 0);
+  /* state[0] is the -f flag; state[1] is the --skip-sig flag */
+  file = open_envblk_file ((state[0].set) ? state[0].arg : 0, state[1].set);
   if (! file)
     return grub_errno;
 
@@ -139,7 +179,8 @@ grub_cmd_load_env (grub_extcmd_context_t ctxt,
   if (! envblk)
     goto fail;
 
-  grub_envblk_iterate (envblk, set_var);
+  /* argc > 0 indicates caller provided a whitelist of variables to read. */
+  grub_envblk_iterate (envblk, argc > 0 ? &whitelist : 0, set_var);
   grub_envblk_close (envblk);
 
  fail:
@@ -149,7 +190,8 @@ grub_cmd_load_env (grub_extcmd_context_t ctxt,
 
 /* Print all variables in current context.  */
 static int
-print_var (const char *name, const char *value)
+print_var (const char *name, const char *value,
+           void *hook_data __attribute__ ((unused)))
 {
   grub_printf ("%s=%s\n", name, value);
   return 0;
@@ -164,7 +206,7 @@ grub_cmd_list_env (grub_extcmd_context_t ctxt,
   grub_file_t file;
   grub_envblk_t envblk;
 
-  file = open_envblk_file ((state[0].set) ? state[0].arg : 0);
+  file = open_envblk_file ((state[0].set) ? state[0].arg : 0, 0);
   if (! file)
     return grub_errno;
 
@@ -172,7 +214,7 @@ grub_cmd_list_env (grub_extcmd_context_t ctxt,
   if (! envblk)
     goto fail;
 
-  grub_envblk_iterate (envblk, print_var);
+  grub_envblk_iterate (envblk, NULL, print_var);
   grub_envblk_close (envblk);
 
  fail:
@@ -333,7 +375,8 @@ grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args)
   if (! argc)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no variable is specified");
 
-  file = open_envblk_file ((state[0].set) ? state[0].arg : 0);
+  file = open_envblk_file ((state[0].set) ? state[0].arg : 0,
+                           1 /* allow untrusted */);
   if (! file)
     return grub_errno;
 
@@ -386,7 +429,8 @@ static grub_extcmd_t cmd_load, cmd_list, cmd_save;
 GRUB_MOD_INIT(loadenv)
 {
   cmd_load =
-    grub_register_extcmd ("load_env", grub_cmd_load_env, 0, N_("[-f FILE]"),
+    grub_register_extcmd ("load_env", grub_cmd_load_env, 0,
+                         N_("[-f FILE] [-s|--skip-sig] [whitelisted_variable_name] [...]"),
                          N_("Load variables from environment block file."),
                          options);
   cmd_list =
index 311927bd83364bf4ceb035262c6d103817b0199c..230e0e9d9abe61a7f74c5eed23a5170bb98f1bd6 100644 (file)
@@ -225,7 +225,8 @@ grub_envblk_delete (grub_envblk_t envblk, const char *name)
 
 void
 grub_envblk_iterate (grub_envblk_t envblk,
-                     int hook (const char *name, const char *value))
+                     void *hook_data,
+                     int hook (const char *name, const char *value, void *hook_data))
 {
   char *p, *pend;
 
@@ -285,7 +286,7 @@ grub_envblk_iterate (grub_envblk_t envblk,
             }
           *q = '\0';
 
-          ret = hook (name, value);
+          ret = hook (name, value, hook_data);
           grub_free (name);
           if (ret)
             return;
index 368ba5368c8c720d8790cf504f806b7b98cc3569..c3e655921709ed1e885e1c13f287156575c56d99 100644 (file)
@@ -35,7 +35,8 @@ grub_envblk_t grub_envblk_open (char *buf, grub_size_t size);
 int grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value);
 void grub_envblk_delete (grub_envblk_t envblk, const char *name);
 void grub_envblk_iterate (grub_envblk_t envblk,
-                          int hook (const char *name, const char *value));
+                          void *hook_data,
+                          int hook (const char *name, const char *value, void *hook_data));
 void grub_envblk_close (grub_envblk_t envblk);
 
 static inline char *
index 9b51acf7dcb99974d6fba4d2ca3532d1c2515cff..591604b4e60ac3260599c355531156e24fb0a8d3 100644 (file)
@@ -185,7 +185,8 @@ open_envblk_file (const char *name)
 }
 
 static int
-print_var (const char *varname, const char *value)
+print_var (const char *varname, const char *value,
+           void *hook_data __attribute__ ((unused)))
 {
   printf ("%s=%s\n", varname, value);
   return 0;
@@ -197,7 +198,7 @@ list_variables (const char *name)
   grub_envblk_t envblk;
 
   envblk = open_envblk_file (name);
-  grub_envblk_iterate (envblk, print_var);
+  grub_envblk_iterate (envblk, NULL, print_var);
   grub_envblk_close (envblk);
 }