Xen Security Advisory CVE-2013-1922 / XSA-48
version 2
qemu-nbd format-guessing due to missing format specification
UPDATES IN VERSION 2
====================
Public release.
ISSUE DESCRIPTION
=================
The qemu-nbd tool (shipped in the Xen hypervisor tools distribution as
qemu-nbd-xen) autodetects the image format.
If a particular disk image is intended to be raw, a guest operating
system administrator could write a header to the image, describing
another format than original one. This could lead to a scenario in
which after restart of that guest, qemu-nbd would detect the new
apparent format of the image, including a specified backing file or
device, which could allow the guest to read any file on the host.
IMPACT
======
qemu-nbd (qemu-nbd-xen) is not used by the toolstack software supplied
with the Xen tree. However, it is built and installed, and so might
be used by host administrators or by toolstacks other than libxl or
xend.
If qemu-nbd is used, a malicious guest administrator may be able to
read any file on the host, depending exactly how.
VULNERABLE SYSTEMS
==================
For Xen systems using libxl (xl) or xend (xm): if neither qemu-nbd-xen
nor qemu-nbd (since qemu-nbd-xen is installed under the latter name in
/usr/lib/xen/bin) is explicitly invoked by scripts or other software
not supplied by the Xen project, the system is not vulnerable.
Xen systems using other toolstacks may be vulnerable if those
toolstacks use qemu-nbd[-xen].
A guest administrator who runs qemu-nbd-xen by hand on a guest may be
exposing themselves to this vulnerability.
Only qemu-xen-upstream is vulnerable; qemu-xen-traditional has a fix
which makes this bug not apply. However, the Xen build system builds
and installs both by default, in some arbitrary order, to the same
filename. So which is installed and might be used is not predictable
unless the qemu-xen-upstream build is entirely disabled.
Only systems with Xen 4.2 and later installed are vulnerable (by
virtue of the presence of Xen) as earlier versions of Xen do not build
qemu-xen-upstream at all.
MITIGATION
==========
No mitigation is available for users of qemu-nbd[-xen]. If you are
using qemu-nbd[-xen] from qemu-xen-upstream on raw image files, then
arranging to use qemu-xen-traditional instead will fail.
If you wish enhanced assurance, removing all copies of of qemu-nbd and
qemu-nbd-xen will provide confidence that this vulnerable utility is
not being used.
RESOLUTION
==========
To resolve the problem, it is necessary to apply the attached patch
(to the qemu-xen-upstream tree).
It is ALSO NECESSARY to ensure that all invocations of qemu-nbd are
provided with an appropriate -f (--format) option. Invoking qemu-nbd
without this option remains unsafe and the patch does not prevent it.
xsa48-4.2.patch Xen 4.2.x (Xen's qemu-upstream-4.2-testing.git)
xsa48-unstable.patch Xen unstable (Xen's qemu-upstream-unstable.git)
$ sha256sum xsa48*
11e5d1f576770fde67e80e3e8c30f9a1af404fe6d07f1c37e96d68677f31435c xsa48-4.2.patch
20dac78bff584951cb706bb76a3394b47525749655dba2f68a6d923faf168fe8 xsa48-unstable.patch
$
xsa48-4.2.patch
Description:
Add -f FMT / --format FMT arg to qemu-nbd
From: "Daniel P. Berrange" <berrange@redhat.com>
Currently the qemu-nbd program will auto-detect the format of
any disk it is given. This behaviour is known to be insecure.
For example, if qemu-nbd initially exposes a 'raw' file to an
unprivileged app, and that app runs
'qemu-img create -f qcow2 -o backing_file=/etc/shadow /dev/nbd0'
then the next time the app is started, the qemu-nbd will now
detect it as a 'qcow2' file and expose /etc/shadow to the
unprivileged app.
The only way to avoid this is to explicitly tell qemu-nbd what
disk format to use on the command line, completely disabling
auto-detection. This patch adds a '-f' / '--format' arg for
this purpose, mirroring what is already available via qemu-img
and qemu commands.
qemu-nbd --format raw -p 9000 evil.img
will now always use raw, regardless of what format 'evil.img'
looks like it contains
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
[Use errx, not err. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
[ This is a security issue, CVE-2013-1922 / XSA-48. ]
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 291cba2..8fbe2cf 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -247,6 +247,7 @@ out:
int main(int argc, char **argv)
{
BlockDriverState *bs;
+ BlockDriver *drv;
off_t dev_offset = 0;
off_t offset = 0;
uint32_t nbdflags = 0;
@@ -256,7 +257,7 @@ int main(int argc, char **argv)
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
off_t fd_size;
- const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
+ const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:t";
struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
@@ -271,6 +272,7 @@ int main(int argc, char **argv)
{ "snapshot", 0, NULL, 's' },
{ "nocache", 0, NULL, 'n' },
{ "shared", 1, NULL, 'e' },
+ { "format", 1, NULL, 'f' },
{ "persistent", 0, NULL, 't' },
{ "verbose", 0, NULL, 'v' },
{ NULL, 0, NULL, 0 }
@@ -292,6 +294,7 @@ int main(int argc, char **argv)
int max_fd;
int persistent = 0;
pthread_t client_thread;
+ const char *fmt = NULL;
/* The client thread uses SIGTERM to interrupt the server. A signal
* handler ensures that "qemu-nbd -v -c" exits with a nice status code.
@@ -368,6 +371,9 @@ int main(int argc, char **argv)
errx(EXIT_FAILURE, "Shared device number must be greater than 0\n");
}
break;
+ case 'f':
+ fmt = optarg;
+ break;
case 't':
persistent = 1;
break;
@@ -478,9 +484,19 @@ int main(int argc, char **argv)
bdrv_init();
atexit(bdrv_close_all);
+ if (fmt) {
+ drv = bdrv_find_format(fmt);
+ if (!drv) {
+ errx(EXIT_FAILURE, "Unknown file format '%s'", fmt);
+ }
+ } else {
+ drv = NULL;
+ }
+
bs = bdrv_new("hda");
srcpath = argv[optind];
- if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) {
+ ret = bdrv_open(bs, srcpath, flags, drv);
+ if (ret < 0) {
errno = -ret;
err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
}
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 44996cc..f56c68e 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -36,6 +36,8 @@ Export Qemu disk image using NBD protocol.
disconnect the specified device
@item -e, --shared=@var{num}
device can be shared by @var{num} clients (default @samp{1})
+@item -f, --format=@var{fmt}
+ force block driver for format @var{fmt} instead of auto-detecting
@item -t, --persistent
don't exit on the last connection
@item -v, --verbose
xsa48-unstable.patch
Description:
Add -f FMT / --format FMT arg to qemu-nbd
From: "Daniel P. Berrange" <berrange@redhat.com>
Currently the qemu-nbd program will auto-detect the format of
any disk it is given. This behaviour is known to be insecure.
For example, if qemu-nbd initially exposes a 'raw' file to an
unprivileged app, and that app runs
'qemu-img create -f qcow2 -o backing_file=/etc/shadow /dev/nbd0'
then the next time the app is started, the qemu-nbd will now
detect it as a 'qcow2' file and expose /etc/shadow to the
unprivileged app.
The only way to avoid this is to explicitly tell qemu-nbd what
disk format to use on the command line, completely disabling
auto-detection. This patch adds a '-f' / '--format' arg for
this purpose, mirroring what is already available via qemu-img
and qemu commands.
qemu-nbd --format raw -p 9000 evil.img
will now always use raw, regardless of what format 'evil.img'
looks like it contains
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
[Use errx, not err. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
[ This is a security issue, CVE-2013-1922 / XSA-48. ]
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 80f08d8..73d8833 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -305,6 +305,7 @@ static void nbd_accept(void *opaque)
int main(int argc, char **argv)
{
BlockDriverState *bs;
+ BlockDriver *drv;
off_t dev_offset = 0;
uint32_t nbdflags = 0;
bool disconnect = false;
@@ -312,7 +313,7 @@ int main(int argc, char **argv)
char *device = NULL;
int port = NBD_DEFAULT_PORT;
off_t fd_size;
- const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
+ const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:t";
struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
@@ -331,6 +332,7 @@ int main(int argc, char **argv)
{ "aio", 1, NULL, QEMU_NBD_OPT_AIO },
#endif
{ "shared", 1, NULL, 'e' },
+ { "format", 1, NULL, 'f' },
{ "persistent", 0, NULL, 't' },
{ "verbose", 0, NULL, 'v' },
{ NULL, 0, NULL, 0 }
@@ -348,6 +350,7 @@ int main(int argc, char **argv)
bool seen_aio = false;
#endif
pthread_t client_thread;
+ const char *fmt = NULL;
/* The client thread uses SIGTERM to interrupt the server. A signal
* handler ensures that "qemu-nbd -v -c" exits with a nice status code.
@@ -442,6 +445,9 @@ int main(int argc, char **argv)
errx(EXIT_FAILURE, "Shared device number must be greater than 0\n");
}
break;
+ case 'f':
+ fmt = optarg;
+ break;
case 't':
persistent = 1;
break;
@@ -543,9 +549,19 @@ int main(int argc, char **argv)
bdrv_init();
atexit(bdrv_close_all);
+ if (fmt) {
+ drv = bdrv_find_format(fmt);
+ if (!drv) {
+ errx(EXIT_FAILURE, "Unknown file format '%s'", fmt);
+ }
+ } else {
+ drv = NULL;
+ }
+
bs = bdrv_new("hda");
srcpath = argv[optind];
- if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) {
+ ret = bdrv_open(bs, srcpath, flags, drv);
+ if (ret < 0) {
errno = -ret;
err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
}
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 6955d90..70abfeb 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -36,6 +36,8 @@ Export QEMU disk image using NBD protocol.
disconnect the specified device
@item -e, --shared=@var{num}
device can be shared by @var{num} clients (default @samp{1})
+@item -f, --format=@var{fmt}
+ force block driver for format @var{fmt} instead of auto-detecting
@item -t, --persistent
don't exit on the last connection
@item -v, --verbose