[libvirt PATCH] src: fix mixup of stack and heap allocated data in auth callback
Richard W.M. Jones
rjones at redhat.com
Thu Mar 5 18:25:20 UTC 2020
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
ACK
Rich.
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index 83326dbaa9..3b5abcc12b 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -164,6 +164,7 @@ EXTRA_DIST = \
> xlconfigdata \
> xmconfigdata \
> xml2vmxdata \
> + virsh-auth.xml \
> virstorageutildata \
> virfilecachedata \
> virresctrldata \
> @@ -406,6 +407,7 @@ test_scripts =
> libvirtd_test_scripts = \
> libvirtd-fail \
> libvirtd-pool \
> + virsh-auth \
> virsh-cpuset \
> virsh-define-dev-segfault \
> virsh-int-overflow \
> diff --git a/tests/virsh-auth b/tests/virsh-auth
> new file mode 100755
> index 0000000000..d548694190
> --- /dev/null
> +++ b/tests/virsh-auth
> @@ -0,0 +1,57 @@
> +#!/usr/bin/env python3
> +# run virsh to validate interactive auth
> +
> +# Copyright (C) 2020 Red Hat, Inc.
> +
> +# This program is free software: you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation, either version 2 of the License, or
> +# (at your option) any later version.
> +
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see
> +# <http://www.gnu.org/licenses/>.
> +
> +import os
> +import os.path
> +import sys
> +import subprocess
> +
> +builddir = os.getenv("abs_top_builddir")
> +if builddir is None:
> + builddir = os.path.join(os.getcwd(), "..")
> +
> +srcdir = os.getenv("abs_top_srcdir")
> +if srcdir is None:
> + srcdir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
> +
> +uri = "test://" + os.path.join(srcdir, "tests", "virsh-auth.xml")
> +
> +virsh = os.path.join(builddir, "tools", "virsh")
> +
> +proc = subprocess.Popen([virsh, "-c", uri, "uri"],
> + universal_newlines=True,
> + start_new_session=True,
> + stdin=subprocess.PIPE,
> + stdout=subprocess.PIPE,
> + stderr=subprocess.PIPE)
> +out, err = proc.communicate("astrochicken")
> +
> +if proc.returncode != 0:
> + print("virsh failed with code %d" % proc.returncode, file=sys.stderr)
> + if out != "":
> + print("stdout=%s" % out)
> + if err != "":
> + print("stderr=%s" % err)
> + sys.exit(1)
> +
> +if uri not in out:
> + print("Expected '%s' in '%s'" % (uri, out), file=sys.stderr)
> + sys.exit(1)
> +
> +sys.exit(0)
> diff --git a/tests/virsh-auth.xml b/tests/virsh-auth.xml
> new file mode 100644
> index 0000000000..a045a0746e
> --- /dev/null
> +++ b/tests/virsh-auth.xml
> @@ -0,0 +1,5 @@
> +<node>
> + <auth>
> + <user>astrochicken</user>
> + </auth>
> +</node>
> --
> 2.24.1
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-builder quickly builds VMs from scratch
http://libguestfs.org/virt-builder.1.html
More information about the libvir-list
mailing list