From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LVrrL-0004r0-Ls for qemu-devel@nongnu.org; Sat, 07 Feb 2009 13:24:55 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LVrrJ-0004pp-W6 for qemu-devel@nongnu.org; Sat, 07 Feb 2009 13:24:54 -0500 Received: from [199.232.76.173] (port=55936 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LVrrJ-0004pb-OC for qemu-devel@nongnu.org; Sat, 07 Feb 2009 13:24:53 -0500 Received: from fmmailgate01.web.de ([217.72.192.221]:46805) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LVrrI-0007Oq-SG for qemu-devel@nongnu.org; Sat, 07 Feb 2009 13:24:53 -0500 Received: from smtp05.web.de (fmsmtp05.dlan.cinetic.de [172.20.4.166]) by fmmailgate01.web.de (Postfix) with ESMTP id 51D9BFCE9CDE for ; Sat, 7 Feb 2009 19:24:52 +0100 (CET) Received: from [88.65.43.151] (helo=[192.168.1.198]) by smtp05.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.110 #277) id 1LVrrH-0003g8-00 for qemu-devel@nongnu.org; Sat, 07 Feb 2009 19:24:52 +0100 Resent-To: qemu-devel Resent-Message-Id: <498DD1F4.7040406@web.de> From: Jan Kiszka Date: Sat, 07 Feb 2009 19:16:28 +0100 Message-ID: <20090207181628.13667.31445.stgit@mchn012c.ww002.siemens.net> In-Reply-To: <20090207181627.13667.9979.stgit@mchn012c.ww002.siemens.net> References: <20090207181627.13667.9979.stgit@mchn012c.ww002.siemens.net> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Sender: jan.kiszka@web.de Subject: [Qemu-devel] [PATCH 08/17] monitor: Rework initial disk password retrieval Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Reading the passwords for encrypted hard disks during early startup is broken (I guess for quiet a while now): - No monitor terminal is ready for input at this point - Forcing all mux'ed terminals into monitor mode can confuse other users of that channels To overcome these issues and to lay the ground for a clean decoupling of monitor terminals, this patch changes the initial password retrieval as follows: - Prevent autostart if there is some encrypted disk - Once the user tries to resume the VM, prompt for all missing passwords - Only resume if all passwords were accepted Signed-off-by: Jan Kiszka --- block.c | 14 ++++++++++- block.h | 4 ++- block_int.h | 1 + hw/usb-msd.c | 6 ++--- hw/usb.h | 5 +++- monitor.c | 44 ++++++++++++++++++++++++++++++++--- monitor.h | 4 +-- vl.c | 73 +++++++++++++++++----------------------------------------- 8 files changed, 85 insertions(+), 66 deletions(-) diff --git a/block.c b/block.c index 5d93de1..3481988 100644 --- a/block.c +++ b/block.c @@ -335,6 +335,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, bs->read_only = 0; bs->is_temporary = 0; bs->encrypted = 0; + bs->valid_key = 0; if (flags & BDRV_O_SNAPSHOT) { BlockDriverState *bs1; @@ -921,6 +922,15 @@ int bdrv_is_encrypted(BlockDriverState *bs) return bs->encrypted; } +int bdrv_key_required(BlockDriverState *bs) +{ + BlockDriverState *backing_hd = bs->backing_hd; + + if (backing_hd && backing_hd->encrypted && !backing_hd->valid_key) + return 1; + return (bs->encrypted && !bs->valid_key); +} + int bdrv_set_key(BlockDriverState *bs, const char *key) { int ret; @@ -933,7 +943,9 @@ int bdrv_set_key(BlockDriverState *bs, const char *key) } if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) return -1; - return bs->drv->bdrv_set_key(bs, key); + ret = bs->drv->bdrv_set_key(bs, key); + bs->valid_key = (ret == 0); + return ret; } void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) diff --git a/block.h b/block.h index a01fa31..5c6eaf9 100644 --- a/block.h +++ b/block.h @@ -103,8 +103,6 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, BlockDriverCompletionFunc *cb, void *opaque); void bdrv_aio_cancel(BlockDriverAIOCB *acb); -int qemu_key_check(BlockDriverState *bs, const char *name); - /* Ensure contents are flushed to disk. */ void bdrv_flush(BlockDriverState *bs); void bdrv_flush_all(void); @@ -144,7 +142,9 @@ BlockDriverState *bdrv_find(const char *name); void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), void *opaque); int bdrv_is_encrypted(BlockDriverState *bs); +int bdrv_key_required(BlockDriverState *bs); int bdrv_set_key(BlockDriverState *bs, const char *key); +int bdrv_query_missing_keys(void); void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque); const char *bdrv_get_device_name(BlockDriverState *bs); diff --git a/block_int.h b/block_int.h index e83fd2c..0b7c8fb 100644 --- a/block_int.h +++ b/block_int.h @@ -96,6 +96,7 @@ struct BlockDriverState { int removable; /* if true, the media can be removed */ int locked; /* if true, the media cannot temporarily be ejected */ int encrypted; /* if true, the media is encrypted */ + int valid_key; /* if true, a valid encryption key has been set */ int sg; /* if true, the device is a /dev/sg* */ /* event callback when inserting/removing */ void (*change_cb)(void *opaque); diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 342b0e8..2b0338d 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -11,6 +11,7 @@ #include "usb.h" #include "block.h" #include "scsi-disk.h" +#include "monitor.h" //#define DEBUG_MSD @@ -513,7 +514,7 @@ static void usb_msd_handle_destroy(USBDevice *dev) qemu_free(s); } -USBDevice *usb_msd_init(const char *filename) +USBDevice *usb_msd_init(const char *filename, BlockDriverState **pbs) { MSDState *s; BlockDriverState *bdrv; @@ -552,9 +553,8 @@ USBDevice *usb_msd_init(const char *filename) bdrv = bdrv_new("usb"); if (bdrv_open2(bdrv, filename, 0, drv) < 0) goto fail; - if (qemu_key_check(bdrv, filename)) - goto fail; s->bs = bdrv; + *pbs = bdrv; s->dev.speed = USB_SPEED_FULL; s->dev.handle_packet = usb_generic_handle_packet; diff --git a/hw/usb.h b/hw/usb.h index 4204808..4cd832d 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -21,6 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + +#include "block.h" + #define USB_TOKEN_SETUP 0x2d #define USB_TOKEN_IN 0x69 /* device -> host */ #define USB_TOKEN_OUT 0xe1 /* host -> device */ @@ -250,7 +253,7 @@ USBDevice *usb_keyboard_init(void); void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *)); /* usb-msd.c */ -USBDevice *usb_msd_init(const char *filename); +USBDevice *usb_msd_init(const char *filename, BlockDriverState **pbs); /* usb-net.c */ USBDevice *usb_net_init(NICInfo *nd); diff --git a/monitor.c b/monitor.c index 61cea11..68bc5e9 100644 --- a/monitor.c +++ b/monitor.c @@ -78,6 +78,8 @@ static uint8_t term_outbuf[1024]; static int term_outbuf_index; static void monitor_start_input(void); +static void monitor_readline(const char *prompt, int is_password, + char *buf, int buf_size); static CPUState *mon_cpu = NULL; @@ -438,7 +440,7 @@ static void do_change_block(const char *device, const char *filename, const char if (eject_device(bs, 0) < 0) return; bdrv_open2(bs, filename, 0, drv); - qemu_key_check(bs, filename); + monitor_read_bdrv_key(bs); } static void do_change_vnc(const char *target, const char *arg) @@ -499,9 +501,24 @@ static void do_stop(void) vm_stop(EXCP_INTERRUPT); } +static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs) +{ + int *err = opaque; + + if (bdrv_key_required(bs)) + *err = monitor_read_bdrv_key(bs); + else + *err = 0; +} + static void do_cont(void) { - vm_start(); + int err = 0; + + bdrv_iterate(encrypted_bdrv_it, &err); + /* only resume the vm if all keys are set and valid */ + if (!err) + vm_start(); } #ifdef CONFIG_GDBSTUB @@ -2856,8 +2873,8 @@ static void monitor_readline_cb(void *opaque, const char *input) monitor_readline_started = 0; } -void monitor_readline(const char *prompt, int is_password, - char *buf, int buf_size) +static void monitor_readline(const char *prompt, int is_password, + char *buf, int buf_size) { int i; int old_focus[MAX_MON]; @@ -2887,3 +2904,22 @@ void monitor_readline(const char *prompt, int is_password, monitor_hd[i]->focus = old_focus[i]; } } + +int monitor_read_bdrv_key(BlockDriverState *bs) +{ + char password[256]; + int i; + + if (!bdrv_is_encrypted(bs)) + return 0; + + monitor_printf("%s (%s) is encrypted.\n", bdrv_get_device_name(bs), + bdrv_get_encrypted_filename(bs)); + for(i = 0; i < 3; i++) { + monitor_readline("Password: ", 1, password, sizeof(password)); + if (bdrv_set_key(bs, password) == 0) + return 0; + monitor_printf("invalid password\n"); + } + return -EPERM; +} diff --git a/monitor.h b/monitor.h index 973c336..8f993f1 100644 --- a/monitor.h +++ b/monitor.h @@ -5,12 +5,10 @@ #include "block.h" void monitor_init(CharDriverState *hd, int show_banner); -void monitor_readline(const char *prompt, int is_password, - char *buf, int buf_size); void monitor_suspend(void); void monitor_resume(void); -int monitor_read_bdrv_key(BlockDriverState *bs, const char *name); +int monitor_read_bdrv_key(BlockDriverState *bs); void monitor_vprintf(const char *fmt, va_list ap); void monitor_printf(const char *fmt, ...) diff --git a/vl.c b/vl.c index b00d009..f8f049a 100644 --- a/vl.c +++ b/vl.c @@ -194,6 +194,7 @@ ram_addr_t ram_size; int nb_nics; NICInfo nd_table[MAX_NICS]; int vm_running; +static int autostart; static int rtc_utc = 1; static int rtc_date_offset = -1; /* -1 means no change */ int cirrus_vga_enabled = 1; @@ -2549,11 +2550,13 @@ static int drive_init(struct drive_opt *arg, int snapshot, bdrv_flags |= BDRV_O_CACHE_WB; else if (cache == 3) /* not specified */ bdrv_flags |= BDRV_O_CACHE_DEF; - if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0 || qemu_key_check(bdrv, file)) { + if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0) { fprintf(stderr, "qemu: could not open disk image %s\n", file); return -1; } + if (bdrv_key_required(bdrv)) + autostart = 0; return 0; } @@ -2600,7 +2603,7 @@ int usb_device_add_dev(USBDevice *dev) return 0; } -static int usb_device_add(const char *devname) +static int usb_device_add(const char *devname, int is_hotplug) { const char *p; USBDevice *dev; @@ -2617,7 +2620,18 @@ static int usb_device_add(const char *devname) } else if (!strcmp(devname, "keyboard")) { dev = usb_keyboard_init(); } else if (strstart(devname, "disk:", &p)) { - dev = usb_msd_init(p); + BlockDriverState *bs; + + dev = usb_msd_init(p, &bs); + if (!dev) + return -1; + if (bdrv_key_required(bs)) { + autostart = 0; + if (is_hotplug && monitor_read_bdrv_key(bs) < 0) { + dev->handle_destroy(dev); + return -1; + } + } } else if (!strcmp(devname, "wacom-tablet")) { dev = usb_wacom_init(); } else if (strstart(devname, "serial:", &p)) { @@ -2698,7 +2712,7 @@ static int usb_device_del(const char *devname) void do_usb_add(const char *devname) { - usb_device_add(devname); + usb_device_add(devname, 1); } void do_usb_del(const char *devname) @@ -4263,45 +4277,6 @@ static const QEMUOption qemu_options[] = { { NULL }, }; -/* password input */ - -int qemu_key_check(BlockDriverState *bs, const char *name) -{ - char password[256]; - int i; - - if (!bdrv_is_encrypted(bs)) - return 0; - - monitor_printf("%s is encrypted.\n", name); - for(i = 0; i < 3; i++) { - monitor_readline("Password: ", 1, password, sizeof(password)); - if (bdrv_set_key(bs, password) == 0) - return 0; - monitor_printf("invalid password\n"); - } - return -EPERM; -} - -static BlockDriverState *get_bdrv(int index) -{ - if (index > nb_drives) - return NULL; - return drives_table[index].bdrv; -} - -static void read_passwords(void) -{ - BlockDriverState *bs; - int i; - - for(i = 0; i < 6; i++) { - bs = get_bdrv(i); - if (bs) - qemu_key_check(bs, bdrv_get_device_name(bs)); - } -} - #ifdef HAS_AUDIO struct soundhw soundhw[] = { #ifdef HAS_AUDIO_CHOICE @@ -4568,7 +4543,6 @@ int main(int argc, char **argv, char **envp) int fds[2]; int tb_size; const char *pid_file = NULL; - int autostart; const char *incoming = NULL; qemu_cache_utils_init(envp); @@ -5551,7 +5525,7 @@ int main(int argc, char **argv, char **envp) /* init USB devices */ if (usb_enabled) { for(i = 0; i < usb_devices_index; i++) { - if (usb_device_add(usb_devices[i]) < 0) { + if (usb_device_add(usb_devices[i], 0) < 0) { fprintf(stderr, "Warning: could not add USB device %s\n", usb_devices[i]); } @@ -5661,13 +5635,8 @@ int main(int argc, char **argv, char **envp) qemu_start_incoming_migration(incoming); } - { - /* XXX: simplify init */ - read_passwords(); - if (autostart) { - vm_start(); - } - } + if (autostart) + vm_start(); if (daemonize) { uint8_t status = 0;