mirror of https://github.com/xemu-project/xemu.git
block: add block driver read only whitelist
We may want to include a driver in the whitelist for read only tasks such as diagnosing or exporting guest data (with libguestfs as a good example). This patch introduces a readonly whitelist option, and for backward compatibility, the old configure option --block-drv-whitelist is now an alias to rw whitelist. Drivers in readonly list is only permitted to open file readonly, and returns -ENOTSUP for RW opening. E.g. To include vmdk readonly, and others read+write: ./configure --target-list=x86_64-softmmu \ --block-drv-rw-whitelist=qcow2,raw,file,qed \ --block-drv-ro-whitelist=vmdk Signed-off-by: Fam Zheng <famz@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
8ddd08c5d1
commit
b64ec4e4ad
43
block.c
43
block.c
|
@ -328,28 +328,40 @@ BlockDriver *bdrv_find_format(const char *format_name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bdrv_is_whitelisted(BlockDriver *drv)
|
static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
|
||||||
{
|
{
|
||||||
static const char *whitelist[] = {
|
static const char *whitelist_rw[] = {
|
||||||
CONFIG_BDRV_WHITELIST
|
CONFIG_BDRV_RW_WHITELIST
|
||||||
|
};
|
||||||
|
static const char *whitelist_ro[] = {
|
||||||
|
CONFIG_BDRV_RO_WHITELIST
|
||||||
};
|
};
|
||||||
const char **p;
|
const char **p;
|
||||||
|
|
||||||
if (!whitelist[0])
|
if (!whitelist_rw[0] && !whitelist_ro[0]) {
|
||||||
return 1; /* no whitelist, anything goes */
|
return 1; /* no whitelist, anything goes */
|
||||||
|
}
|
||||||
|
|
||||||
for (p = whitelist; *p; p++) {
|
for (p = whitelist_rw; *p; p++) {
|
||||||
if (!strcmp(drv->format_name, *p)) {
|
if (!strcmp(drv->format_name, *p)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (read_only) {
|
||||||
|
for (p = whitelist_ro; *p; p++) {
|
||||||
|
if (!strcmp(drv->format_name, *p)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockDriver *bdrv_find_whitelisted_format(const char *format_name)
|
BlockDriver *bdrv_find_whitelisted_format(const char *format_name,
|
||||||
|
bool read_only)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bdrv_find_format(format_name);
|
BlockDriver *drv = bdrv_find_format(format_name);
|
||||||
return drv && bdrv_is_whitelisted(drv) ? drv : NULL;
|
return drv && bdrv_is_whitelisted(drv, read_only) ? drv : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct CreateCo {
|
typedef struct CreateCo {
|
||||||
|
@ -684,10 +696,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
||||||
|
|
||||||
trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
|
trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
|
||||||
|
|
||||||
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* bdrv_open() with directly using a protocol as drv. This layer is already
|
/* bdrv_open() with directly using a protocol as drv. This layer is already
|
||||||
* opened, so assign it to bs (while file becomes a closed BlockDriverState)
|
* opened, so assign it to bs (while file becomes a closed BlockDriverState)
|
||||||
* and return immediately. */
|
* and return immediately. */
|
||||||
|
@ -698,9 +706,15 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
||||||
|
|
||||||
bs->open_flags = flags;
|
bs->open_flags = flags;
|
||||||
bs->buffer_alignment = 512;
|
bs->buffer_alignment = 512;
|
||||||
|
open_flags = bdrv_open_flags(bs, flags);
|
||||||
|
bs->read_only = !(open_flags & BDRV_O_RDWR);
|
||||||
|
|
||||||
|
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */
|
assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */
|
||||||
if ((flags & BDRV_O_RDWR) && (flags & BDRV_O_COPY_ON_READ)) {
|
if (!bs->read_only && (flags & BDRV_O_COPY_ON_READ)) {
|
||||||
bdrv_enable_copy_on_read(bs);
|
bdrv_enable_copy_on_read(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,9 +728,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
||||||
bs->opaque = g_malloc0(drv->instance_size);
|
bs->opaque = g_malloc0(drv->instance_size);
|
||||||
|
|
||||||
bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
|
bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
|
||||||
open_flags = bdrv_open_flags(bs, flags);
|
|
||||||
|
|
||||||
bs->read_only = !(open_flags & BDRV_O_RDWR);
|
|
||||||
|
|
||||||
/* Open the image, either directly or using a protocol */
|
/* Open the image, either directly or using a protocol */
|
||||||
if (drv->bdrv_file_open) {
|
if (drv->bdrv_file_open) {
|
||||||
|
@ -801,7 +812,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
|
||||||
/* Find the right block driver */
|
/* Find the right block driver */
|
||||||
drvname = qdict_get_try_str(options, "driver");
|
drvname = qdict_get_try_str(options, "driver");
|
||||||
if (drvname) {
|
if (drvname) {
|
||||||
drv = bdrv_find_whitelisted_format(drvname);
|
drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR));
|
||||||
qdict_del(options, "driver");
|
qdict_del(options, "driver");
|
||||||
} else if (filename) {
|
} else if (filename) {
|
||||||
drv = bdrv_find_protocol(filename);
|
drv = bdrv_find_protocol(filename);
|
||||||
|
|
|
@ -477,7 +477,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||||
error_printf("\n");
|
error_printf("\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
drv = bdrv_find_whitelisted_format(buf);
|
drv = bdrv_find_whitelisted_format(buf, ro);
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
error_report("'%s' invalid format", buf);
|
error_report("'%s' invalid format", buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1096,7 +1096,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format) {
|
if (format) {
|
||||||
drv = bdrv_find_whitelisted_format(format);
|
drv = bdrv_find_whitelisted_format(format, bs->read_only);
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
|
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -123,7 +123,8 @@ interp_prefix="/usr/gnemul/qemu-%M"
|
||||||
static="no"
|
static="no"
|
||||||
cross_prefix=""
|
cross_prefix=""
|
||||||
audio_drv_list=""
|
audio_drv_list=""
|
||||||
block_drv_whitelist=""
|
block_drv_rw_whitelist=""
|
||||||
|
block_drv_ro_whitelist=""
|
||||||
host_cc="cc"
|
host_cc="cc"
|
||||||
libs_softmmu=""
|
libs_softmmu=""
|
||||||
libs_tools=""
|
libs_tools=""
|
||||||
|
@ -708,7 +709,9 @@ for opt do
|
||||||
;;
|
;;
|
||||||
--audio-drv-list=*) audio_drv_list="$optarg"
|
--audio-drv-list=*) audio_drv_list="$optarg"
|
||||||
;;
|
;;
|
||||||
--block-drv-whitelist=*) block_drv_whitelist=`echo "$optarg" | sed -e 's/,/ /g'`
|
--block-drv-rw-whitelist=*|--block-drv-whitelist=*) block_drv_rw_whitelist=`echo "$optarg" | sed -e 's/,/ /g'`
|
||||||
|
;;
|
||||||
|
--block-drv-ro-whitelist=*) block_drv_ro_whitelist=`echo "$optarg" | sed -e 's/,/ /g'`
|
||||||
;;
|
;;
|
||||||
--enable-debug-tcg) debug_tcg="yes"
|
--enable-debug-tcg) debug_tcg="yes"
|
||||||
;;
|
;;
|
||||||
|
@ -1049,7 +1052,12 @@ echo " --disable-cocoa disable Cocoa (Mac OS X only)"
|
||||||
echo " --enable-cocoa enable Cocoa (default on Mac OS X)"
|
echo " --enable-cocoa enable Cocoa (default on Mac OS X)"
|
||||||
echo " --audio-drv-list=LIST set audio drivers list:"
|
echo " --audio-drv-list=LIST set audio drivers list:"
|
||||||
echo " Available drivers: $audio_possible_drivers"
|
echo " Available drivers: $audio_possible_drivers"
|
||||||
echo " --block-drv-whitelist=L set block driver whitelist"
|
echo " --block-drv-whitelist=L Same as --block-drv-rw-whitelist=L"
|
||||||
|
echo " --block-drv-rw-whitelist=L"
|
||||||
|
echo " set block driver read-write whitelist"
|
||||||
|
echo " (affects only QEMU, not qemu-img)"
|
||||||
|
echo " --block-drv-ro-whitelist=L"
|
||||||
|
echo " set block driver read-only whitelist"
|
||||||
echo " (affects only QEMU, not qemu-img)"
|
echo " (affects only QEMU, not qemu-img)"
|
||||||
echo " --enable-mixemu enable mixer emulation"
|
echo " --enable-mixemu enable mixer emulation"
|
||||||
echo " --disable-xen disable xen backend driver support"
|
echo " --disable-xen disable xen backend driver support"
|
||||||
|
@ -3481,7 +3489,8 @@ echo "curses support $curses"
|
||||||
echo "curl support $curl"
|
echo "curl support $curl"
|
||||||
echo "mingw32 support $mingw32"
|
echo "mingw32 support $mingw32"
|
||||||
echo "Audio drivers $audio_drv_list"
|
echo "Audio drivers $audio_drv_list"
|
||||||
echo "Block whitelist $block_drv_whitelist"
|
echo "Block whitelist (rw) $block_drv_rw_whitelist"
|
||||||
|
echo "Block whitelist (ro) $block_drv_ro_whitelist"
|
||||||
echo "Mixer emulation $mixemu"
|
echo "Mixer emulation $mixemu"
|
||||||
echo "VirtFS support $virtfs"
|
echo "VirtFS support $virtfs"
|
||||||
echo "VNC support $vnc"
|
echo "VNC support $vnc"
|
||||||
|
@ -3662,7 +3671,8 @@ fi
|
||||||
if test "$audio_win_int" = "yes" ; then
|
if test "$audio_win_int" = "yes" ; then
|
||||||
echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak
|
echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
echo "CONFIG_BDRV_WHITELIST=$block_drv_whitelist" >> $config_host_mak
|
echo "CONFIG_BDRV_RW_WHITELIST=$block_drv_rw_whitelist" >> $config_host_mak
|
||||||
|
echo "CONFIG_BDRV_RO_WHITELIST=$block_drv_ro_whitelist" >> $config_host_mak
|
||||||
if test "$mixemu" = "yes" ; then
|
if test "$mixemu" = "yes" ; then
|
||||||
echo "CONFIG_MIXEMU=y" >> $config_host_mak
|
echo "CONFIG_MIXEMU=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -780,11 +780,13 @@ static int blk_connect(struct XenDevice *xendev)
|
||||||
{
|
{
|
||||||
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
||||||
int pers, index, qflags;
|
int pers, index, qflags;
|
||||||
|
bool readonly = true;
|
||||||
|
|
||||||
/* read-only ? */
|
/* read-only ? */
|
||||||
qflags = BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO;
|
qflags = BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO;
|
||||||
if (strcmp(blkdev->mode, "w") == 0) {
|
if (strcmp(blkdev->mode, "w") == 0) {
|
||||||
qflags |= BDRV_O_RDWR;
|
qflags |= BDRV_O_RDWR;
|
||||||
|
readonly = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* init qemu block driver */
|
/* init qemu block driver */
|
||||||
|
@ -795,8 +797,10 @@ static int blk_connect(struct XenDevice *xendev)
|
||||||
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
||||||
blkdev->bs = bdrv_new(blkdev->dev);
|
blkdev->bs = bdrv_new(blkdev->dev);
|
||||||
if (blkdev->bs) {
|
if (blkdev->bs) {
|
||||||
if (bdrv_open(blkdev->bs, blkdev->filename, NULL, qflags,
|
BlockDriver *drv = bdrv_find_whitelisted_format(blkdev->fileproto,
|
||||||
bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
|
readonly);
|
||||||
|
if (bdrv_open(blkdev->bs,
|
||||||
|
blkdev->filename, NULL, qflags, drv) != 0) {
|
||||||
bdrv_delete(blkdev->bs);
|
bdrv_delete(blkdev->bs);
|
||||||
blkdev->bs = NULL;
|
blkdev->bs = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,8 @@ void bdrv_init(void);
|
||||||
void bdrv_init_with_whitelist(void);
|
void bdrv_init_with_whitelist(void);
|
||||||
BlockDriver *bdrv_find_protocol(const char *filename);
|
BlockDriver *bdrv_find_protocol(const char *filename);
|
||||||
BlockDriver *bdrv_find_format(const char *format_name);
|
BlockDriver *bdrv_find_format(const char *format_name);
|
||||||
BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
|
BlockDriver *bdrv_find_whitelisted_format(const char *format_name,
|
||||||
|
bool readonly);
|
||||||
int bdrv_create(BlockDriver *drv, const char* filename,
|
int bdrv_create(BlockDriver *drv, const char* filename,
|
||||||
QEMUOptionParameter *options);
|
QEMUOptionParameter *options);
|
||||||
int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
|
int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
|
||||||
|
|
|
@ -34,8 +34,15 @@ case $line in
|
||||||
done
|
done
|
||||||
echo ""
|
echo ""
|
||||||
;;
|
;;
|
||||||
CONFIG_BDRV_WHITELIST=*)
|
CONFIG_BDRV_RW_WHITELIST=*)
|
||||||
echo "#define CONFIG_BDRV_WHITELIST \\"
|
echo "#define CONFIG_BDRV_RW_WHITELIST\\"
|
||||||
|
for drv in ${line#*=}; do
|
||||||
|
echo " \"${drv}\",\\"
|
||||||
|
done
|
||||||
|
echo " NULL"
|
||||||
|
;;
|
||||||
|
CONFIG_BDRV_RO_WHITELIST=*)
|
||||||
|
echo "#define CONFIG_BDRV_RO_WHITELIST\\"
|
||||||
for drv in ${line#*=}; do
|
for drv in ${line#*=}; do
|
||||||
echo " \"${drv}\",\\"
|
echo " \"${drv}\",\\"
|
||||||
done
|
done
|
||||||
|
|
Loading…
Reference in New Issue