grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v3] cryptodisk: allow user to retry failed passphrase


From: Forest
Subject: Re: [PATCH v3] cryptodisk: allow user to retry failed passphrase
Date: Sat, 27 Apr 2024 17:31:31 -0700

Please ignore this rev in favor of v4, coming soon.

(I want to simplify the stale-errno guard around grub_strtoul().)


On Sat, 27 Apr 2024 17:15:42 -0700, Forest wrote:

>Give the user a chance to re-enter their cryptodisk passphrase after a typo,
>rather than immediately failing (and likely dumping them into a grub shell).
>
>By default, we allow 3 tries before giving up. A value in the
>cryptodisk_passphrase_tries environment variable will override this default.
>
>The user can give up early by entering an empty passphrase, just as they
>could before this patch.
>
>Signed-off-by: Forest <forestix@nom.one>
>---
> docs/grub.texi              |  9 +++++
> grub-core/disk/cryptodisk.c | 74 +++++++++++++++++++++++++++++--------
> 2 files changed, 67 insertions(+), 16 deletions(-)
>
>diff --git a/docs/grub.texi b/docs/grub.texi
>index a225f9a88..6ac603a32 100644
>--- a/docs/grub.texi
>+++ b/docs/grub.texi
>@@ -3277,6 +3277,7 @@ These variables have special meaning to GRUB.
> * color_normal::
> * config_directory::
> * config_file::
>+* cryptodisk_passphrase_tries::
> * debug::
> * default::
> * fallback::
>@@ -3441,6 +3442,14 @@ processed by commands @command{configfile} 
>(@pxref{configfile}) or @command{norm
> (@pxref{normal}).  It is restored to the previous value when command 
> completes.
> 
> 
>+@node cryptodisk_passphrase_tries
>+@subsection cryptodisk_passphrase_tries
>+
>+When prompting the user for a cryptodisk passphrase, allow this many attempts
>+before giving up. The default is @samp{3}. (The user can give up early by
>+entering an empty passphrase.)
>+
>+
> @node debug
> @subsection debug
> 
>diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
>index 2246af51b..4fa7dc58d 100644
>--- a/grub-core/disk/cryptodisk.c
>+++ b/grub-core/disk/cryptodisk.c
>@@ -17,6 +17,7 @@
>  */
> 
> #include <grub/cryptodisk.h>
>+#include <grub/env.h>
> #include <grub/mm.h>
> #include <grub/misc.h>
> #include <grub/dl.h>
>@@ -1063,6 +1064,8 @@ grub_cryptodisk_scan_device_real (const char *name,
>   grub_cryptodisk_dev_t cr;
>   struct cryptodisk_read_hook_ctx read_hook_data = {0};
>   int askpass = 0;
>+  unsigned long tries = 3;
>+  const char *tries_env;
>   char *part = NULL;
> 
>   dev = grub_cryptodisk_get_by_source_disk (source);
>@@ -1114,32 +1117,71 @@ grub_cryptodisk_scan_device_real (const char *name,
>     if (!dev)
>       continue;
> 
>-    if (!cargs->key_len)
>+    if (cargs->key_len)
>+      {
>+      ret = cr->recover_key (source, dev, cargs);
>+      if (ret != GRUB_ERR_NONE)
>+        goto error;
>+      }
>+    else
>       {
>       /* Get the passphrase from the user, if no key data. */
>       askpass = 1;
>-      part = grub_partition_get_name (source->partition);
>-      grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
>-                   source->partition != NULL ? "," : "",
>-                   part != NULL ? part : N_("UNKNOWN"),
>-                   dev->uuid);
>-      grub_free (part);
>-
>       cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
>       if (cargs->key_data == NULL)
>         goto error_no_close;
> 
>-      if (!grub_password_get ((char *) cargs->key_data, 
>GRUB_CRYPTODISK_MAX_PASSPHRASE))
>+      tries_env = grub_env_get ("cryptodisk_passphrase_tries");
>+      if (tries_env != NULL && tries_env[0] != '\0')
>         {
>-          grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
>-          goto error;
>+          const char *p = NULL;
>+          tries = grub_strtoul (tries_env, &p, 0);
>+          if (*p != '\0')
>+            {
>+              /* Account for grub_strtoul() ignoring trailing text. */
>+              grub_err_t err = grub_errno;
>+              if (p > tries_env && tries != ~0UL)
>+                err = GRUB_ERR_BAD_NUMBER;
>+
>+              grub_error (err,
>+                          N_("non-numeric or invalid value for 
>cryptodisk_passphrase_tries: `%s'"),
>+                          tries_env);
>+              goto error;
>+            }
>         }
>-      cargs->key_len = grub_strlen ((char *) cargs->key_data);
>-      }
> 
>-    ret = cr->recover_key (source, dev, cargs);
>-    if (ret != GRUB_ERR_NONE)
>-      goto error;
>+      for (; tries > 0; tries--)
>+        {
>+          part = grub_partition_get_name (source->partition);
>+          grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), 
>source->name,
>+                       source->partition != NULL ? "," : "",
>+                       part != NULL ? part : N_("UNKNOWN"),
>+                       dev->uuid);
>+          grub_free (part);
>+
>+          if (!grub_password_get ((char *) cargs->key_data, 
>GRUB_CRYPTODISK_MAX_PASSPHRASE))
>+            {
>+              grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
>+              goto error;
>+            }
>+          cargs->key_len = grub_strlen ((char *) cargs->key_data);
>+
>+          ret = cr->recover_key (source, dev, cargs);
>+          if (ret == GRUB_ERR_NONE)
>+            break;
>+          if (ret != GRUB_ERR_ACCESS_DENIED || tries == 1)
>+            goto error;
>+          grub_puts_ (N_("Invalid passphrase."));
>+
>+          /*
>+           * Since recover_key() calls a function that returns grub_errno,
>+           * a leftover error value from a previously rejected passphrase
>+           * will trigger a phantom failure. We therefore clear it before
>+           * trying a new passphrase.
>+           */
>+          grub_errno = GRUB_ERR_NONE;
>+        }
>+      }
> 
>     ret = grub_cryptodisk_insert (dev, name, source);
>     if (ret != GRUB_ERR_NONE)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]