提交 b64ec4e4 编写于 作者: F Fam Zheng 提交者: Kevin Wolf

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: NFam Zheng <famz@redhat.com>
Signed-off-by: NKevin Wolf <kwolf@redhat.com>
上级 8ddd08c5
...@@ -328,28 +328,40 @@ BlockDriver *bdrv_find_format(const char *format_name) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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" ...@@ -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 ...@@ -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)" ...@@ -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" ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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 ...@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册