[libvirt PATCH] src: fix mixup of stack and heap allocated data in auth callback
Daniel P. Berrangé
berrange at redhat.com
Fri Mar 6 13:16:24 UTC 2020
On Thu, Mar 05, 2020 at 06:25:20PM +0000, Richard W.M. Jones wrote:
> On Thu, Mar 05, 2020 at 04:54:10PM +0000, Daniel P. Berrangé wrote:
> > In the following recent change:
> >
> > commit db72866310d1e520efa8ed2d4589bdb5e76a1c95
> > Author: Daniel P. Berrangé <berrange at redhat.com>
> > Date: Tue Jan 14 10:40:52 2020 +0000
> >
> > util: add API for reading password from the console
> >
> > the fact that "bufptr" pointer may point to either heap or stack
> > allocated data was overlooked. As a result, when the strdup was
> > removed, we ended up returning a pointer to the local stack to
> > the caller. When the caller referenced this stack pointer they
> > got out garbage which fairly quickly resulted in a crash.
> >
> > Switching from fgets() to getline() lets to avoid the need for
> > the stack allocated buffer entirely, which makes both cases
> > of the switch consistent.
> >
> > Test case addition is inspired by the libguestfs test which
> > caught this bug.
> >
> > Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
> > ---
> > src/libvirt.c | 30 +++++++++++------------
> > tests/Makefile.am | 2 ++
> > tests/virsh-auth | 57 ++++++++++++++++++++++++++++++++++++++++++++
> > tests/virsh-auth.xml | 5 ++++
> > 4 files changed, 79 insertions(+), 15 deletions(-)
> > create mode 100755 tests/virsh-auth
> > create mode 100644 tests/virsh-auth.xml
> >
> > diff --git a/src/libvirt.c b/src/libvirt.c
> > index a30eaa7590..cc9c2eb5a2 100644
> > --- a/src/libvirt.c
> > +++ b/src/libvirt.c
> > @@ -110,9 +110,8 @@ virConnectAuthCallbackDefault(virConnectCredentialPtr cred,
> > size_t i;
> >
> > for (i = 0; i < ncred; i++) {
> > - char buf[1024];
> > - char *bufptr = buf;
> > - size_t len;
> > + char *buf = NULL;
> > + size_t len = 0;
> >
> > switch (cred[i].type) {
> > case VIR_CRED_EXTERNAL: {
> > @@ -136,16 +135,17 @@ virConnectAuthCallbackDefault(virConnectCredentialPtr cred,
> > if (fflush(stdout) != 0)
> > return -1;
> >
> > - if (!fgets(buf, sizeof(buf), stdin)) {
> > - if (feof(stdin)) { /* Treat EOF as "" */
> > - buf[0] = '\0';
> > - break;
> > + if (getline(&buf, &len, stdin) < 0) {
> > + if (!feof(stdin)) {
> > + return -1;
> > }
> > - return -1;
> > + /* Use creddefault on EOF */
> > + buf = NULL;
> > + } else {
> > + len = strlen(buf);
> > + if (len != 0 && buf[len-1] == '\n')
> > + buf[len-1] = '\0';
> > }
> > - len = strlen(buf);
> > - if (len != 0 && buf[len-1] == '\n')
> > - buf[len-1] = '\0';
> > break;
> >
> > case VIR_CRED_PASSPHRASE:
> > @@ -155,9 +155,9 @@ virConnectAuthCallbackDefault(virConnectCredentialPtr cred,
> > if (fflush(stdout) != 0)
> > return -1;
> >
> > - bufptr = virGetPassword();
> > - if (STREQ(bufptr, ""))
> > - VIR_FREE(bufptr);
> > + buf = virGetPassword();
> > + if (STREQ(buf, ""))
> > + VIR_FREE(buf);
> > break;
> >
> > default:
> > @@ -165,7 +165,7 @@ virConnectAuthCallbackDefault(virConnectCredentialPtr cred,
> > }
> >
> > if (cred[i].type != VIR_CRED_EXTERNAL) {
> > - cred[i].result = bufptr ? bufptr : g_strdup(cred[i].defresult ? cred[i].defresult : "");
> > + cred[i].result = buf ? buf : g_strdup(cred[i].defresult ? cred[i].defresult : "");
> > cred[i].resultlen = strlen(cred[i].result);
> > }
> > }
>
> It's clearly better to use getline here instead of fgets and
> the large fixed-size stack buffer, so
Damn, doesn't exist on Mingw, so I'll have to rework to keep
fgets and fix it differently.
Regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
More information about the libvir-list
mailing list