On Thu, Aug 09, 2018 at 08:45:03AM +0200, Theo Buehler wrote:
> On Wed, Aug 08, 2018 at 05:53:56PM +0200, Theo Buehler wrote:
> > On Wed, Aug 08, 2018 at 02:45:29PM +0100, Ricardo Mestre wrote:
> > > Hi,
> > > 
> > > When openssl(1) passwd is invoked without passing in the `password' as 
> > > argument
> > > , meaning interactively, and if the password is 10 or more characters it 
> > > will
> > > show the following memory corruption error, and using -crypt which is the
> > > default:
> > > 
> > > openssl(43025) in free(): chunck canary corrupted 0x13a8dc4a1bb0 0xa@0xa
> > > 
> > > pw_len is set to 8, then passwd_malloc_size is set to pw_len + 2 in order 
> > > to be
> > > able to warn the user that the password will be truncated then it calls
> > > EVP_read_pw_string(3) which allocates the space size of the input buffer, 
> > > in
> > > this case password_malloc_size plus 1 for the NUL-termination character 
> > > through
> > > strlcpy(3).
> > > 
> > > When we finally call free(password_malloc) the sizes will differ and the 
> > > memory
> > > will be corrupted, in order to solve this when we allocate memory for the 
> > > input
> > > buffer we need to add plus 1 for the NUL-termination character.
> > > 
> > > Comments? OK?
> > 
> > Nice find. I think this is an off-by-one in EVP_read_pw_string_min()'s
> > usage of UI_add_input_string() (and UI_add_verify_string()). The man
> > page explicitly says that NUL is *not* counted in minlen and maxlen.
> > 
> >      UI_add_input_string() and UI_add_verify_string() add a prompt to ui, as
> >      well as flags and a result buffer and the desired minimum and maximum
> >      sizes of the result, not counting the final NUL character.
> > 
> > Notice that EVP_read_pw_string(buf, sizeof buf, ...) is a common enough
> > idiom.  All these are subject to a similar buffer overrun.  On the other
> > hand, everywhere else our tree has the correct usage of
> > 
> >     UI_add_input_string(ui, prompt, flags, buf, 0, sizeof(buf) - 1),
> > 
> > so I believe we should fix this in EVP_read_pw_string_min() as follows:
> 
> I got some oks on this, but here's a diff that I like better since it's
> more defensive.
> 
> First, ints min and len only make sense if they're non-negative, so
> let's check for that. Second, let's check for the maxlen < minlen
> situation as the UI_* family of functions doesn't seem to do that.
> Third, it seems easier to cap len at BUFSIZ instead of repeating the use
> of the ternary operator.
> 
> I forgot to mention that this diff also aligns EVP_read_pw_string() with
> the documented behavior whereas currently buf would need to be of size
> length+1 to avoid the buffer overrun.

Right after sending I noticed that I had the checks in the wrong order.
Sorry about that.

Index: evp/evp_key.c
===================================================================
RCS file: /var/cvs/src/lib/libcrypto/evp/evp_key.c,v
retrieving revision 1.24
diff -u -p -r1.24 evp_key.c
--- evp/evp_key.c       29 Jan 2017 17:49:23 -0000      1.24
+++ evp/evp_key.c       9 Aug 2018 07:08:20 -0000
@@ -101,17 +101,20 @@ EVP_read_pw_string_min(char *buf, int mi
        char buff[BUFSIZ];
        UI *ui;
 
+       if (len > BUFSIZ)
+               len = BUFSIZ;
+       if (min < 0 || len - 1 < min)
+               return -1;
        if ((prompt == NULL) && (prompt_string[0] != '\0'))
                prompt = prompt_string;
        ui = UI_new();
        if (ui == NULL)
                return -1;
-       if (UI_add_input_string(ui, prompt, 0, buf, min,
-           (len >= BUFSIZ) ? BUFSIZ - 1 : len) < 0)
+       if (UI_add_input_string(ui, prompt, 0, buf, min, len - 1) < 0)
                return -1;
        if (verify) {
-               if (UI_add_verify_string(ui, prompt, 0, buff, min,
-                   (len >= BUFSIZ) ? BUFSIZ - 1 : len, buf) < 0)
+               if (UI_add_verify_string(ui, prompt, 0, buff, min, len - 1, buf)
+                   < 0)
                        return -1;
        }
        ret = UI_process(ui);

Reply via email to