static int nfs_parse_uri(const char *filename, QDict *options, Error **errp) { URI *uri = NULL; QueryParams *qp = NULL; int ret = -EINVAL, i; uri = uri_parse(filename); if (!uri) { error_setg(errp, "Invalid URI specified"); goto out; } if (strcmp(uri->scheme, "nfs") != 0) { error_setg(errp, "URI scheme must be 'nfs'"); goto out; } if (!uri->server) { error_setg(errp, "missing hostname in URI"); goto out; } if (!uri->path) { error_setg(errp, "missing file path in URI"); goto out; } qp = query_params_parse(uri->query); if (!qp) { error_setg(errp, "could not parse query parameters"); goto out; } qdict_put(options, "server.host", qstring_from_str(uri->server)); qdict_put(options, "server.type", qstring_from_str("inet")); qdict_put(options, "path", qstring_from_str(uri->path)); for (i = 0; i < qp->n; i++) { if (!qp->p[i].value) { error_setg(errp, "Value for NFS parameter expected: %s", qp->p[i].name); goto out; } if (parse_uint_full(qp->p[i].value, NULL, 0)) { error_setg(errp, "Illegal value for NFS parameter: %s", qp->p[i].name); goto out; } if (!strcmp(qp->p[i].name, "uid")) { qdict_put(options, "user", qstring_from_str(qp->p[i].value)); } else if (!strcmp(qp->p[i].name, "gid")) { qdict_put(options, "group", qstring_from_str(qp->p[i].value)); } else if (!strcmp(qp->p[i].name, "tcp-syncnt")) { qdict_put(options, "tcp-syn-count", qstring_from_str(qp->p[i].value)); } else if (!strcmp(qp->p[i].name, "readahead")) { qdict_put(options, "readahead-size", qstring_from_str(qp->p[i].value)); } else if (!strcmp(qp->p[i].name, "pagecache")) { qdict_put(options, "page-cache-size", qstring_from_str(qp->p[i].value)); } else if (!strcmp(qp->p[i].name, "debug")) { qdict_put(options, "debug-level", qstring_from_str(qp->p[i].value)); } else { error_setg(errp, "Unknown NFS parameter name: %s", qp->p[i].name); goto out; } } ret = 0; out: if (qp) { query_params_free(qp); } if (uri) { uri_free(uri); } return ret; }
static int pci_ivshmem_init(PCIDevice *dev) { IVShmemState *s = IVSHMEM(dev); uint8_t *pci_conf; if (s->sizearg == NULL) s->ivshmem_size = 4 << 20; /* 4 MB default */ else { s->ivshmem_size = ivshmem_get_size(s); } register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load, dev); /* IRQFD requires MSI */ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) && !ivshmem_has_feature(s, IVSHMEM_MSI)) { fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n"); exit(1); } /* check that role is reasonable */ if (s->role) { if (strncmp(s->role, "peer", 5) == 0) { s->role_val = IVSHMEM_PEER; } else if (strncmp(s->role, "master", 7) == 0) { s->role_val = IVSHMEM_MASTER; } else { fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n"); exit(1); } } else { s->role_val = IVSHMEM_MASTER; /* default */ } if (s->role_val == IVSHMEM_PEER) { error_setg(&s->migration_blocker, "Migration is disabled when using feature 'peer mode' in device 'ivshmem'"); migrate_add_blocker(s->migration_blocker); } pci_conf = dev->config; pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY; pci_config_set_interrupt_pin(pci_conf, 1); s->shm_fd = 0; memory_region_init_io(&s->ivshmem_mmio, OBJECT(s), &ivshmem_mmio_ops, s, "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE); /* region for registers*/ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ivshmem_mmio); memory_region_init(&s->bar, OBJECT(s), "ivshmem-bar2-container", s->ivshmem_size); s->ivshmem_attr = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH; if (s->ivshmem_64bit) { s->ivshmem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64; } if ((s->server_chr != NULL) && (strncmp(s->server_chr->filename, "unix:", 5) == 0)) { /* if we get a UNIX socket as the parameter we will talk * to the ivshmem server to receive the memory region */ if (s->shmobj != NULL) { fprintf(stderr, "WARNING: do not specify both 'chardev' " "and 'shm' with ivshmem\n"); } IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n", s->server_chr->filename); if (ivshmem_has_feature(s, IVSHMEM_MSI)) { ivshmem_setup_msi(s); } /* we allocate enough space for 16 guests and grow as needed */ s->nb_peers = 16; s->vm_id = -1; /* allocate/initialize space for interrupt handling */ s->peers = g_malloc0(s->nb_peers * sizeof(Peer)); pci_register_bar(dev, 2, s->ivshmem_attr, &s->bar); s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *)); qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read, ivshmem_event, s); } else { /* just map the file immediately, we're not using a server */ int fd; if (s->shmobj == NULL) { fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n"); exit(1); } IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj); /* try opening with O_EXCL and if it succeeds zero the memory * by truncating to 0 */ if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL, S_IRWXU|S_IRWXG|S_IRWXO)) > 0) { /* truncate file to length PCI device's memory */ if (ftruncate(fd, s->ivshmem_size) != 0) { fprintf(stderr, "ivshmem: could not truncate shared file\n"); } } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR, S_IRWXU|S_IRWXG|S_IRWXO)) < 0) { fprintf(stderr, "ivshmem: could not open shared file\n"); exit(-1); } if (check_shm_size(s, fd) == -1) { exit(-1); } create_shared_memory_BAR(s, fd); } dev->config_write = ivshmem_write_config; return 0; }
static void kvm_pit_realizefn(DeviceState *dev, Error **errp) { PITCommonState *pit = PIT_COMMON(dev); KVMPITClass *kpc = KVM_PIT_GET_CLASS(dev); KVMPITState *s = KVM_PIT(pit); struct kvm_pit_config config = { .flags = 0, }; int ret; if (kvm_check_extension(kvm_state, KVM_CAP_PIT2)) { ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT2, &config); } else { ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT); } if (ret < 0) { error_setg(errp, "Create kernel PIC irqchip failed: %s", strerror(ret)); return; } switch (s->lost_tick_policy) { case LOST_TICK_POLICY_DELAY: break; /* enabled by default */ case LOST_TICK_POLICY_DISCARD: if (kvm_check_extension(kvm_state, KVM_CAP_REINJECT_CONTROL)) { struct kvm_reinject_control control = { .pit_reinject = 0 }; ret = kvm_vm_ioctl(kvm_state, KVM_REINJECT_CONTROL, &control); if (ret < 0) { error_setg(errp, "Can't disable in-kernel PIT reinjection: %s", strerror(ret)); return; } } break; default: error_setg(errp, "Lost tick policy not supported."); return; } memory_region_init_reservation(&pit->ioports, NULL, "kvm-pit", 4); qdev_init_gpio_in(dev, kvm_pit_irq_control, 1); qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s); kpc->parent_realize(dev, errp); } static Property kvm_pit_properties[] = { DEFINE_PROP_UINT32("iobase", PITCommonState, iobase, -1), DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", KVMPITState, lost_tick_policy, LOST_TICK_POLICY_DELAY), DEFINE_PROP_END_OF_LIST(), }; static void kvm_pit_class_init(ObjectClass *klass, void *data) { KVMPITClass *kpc = KVM_PIT_CLASS(klass); PITCommonClass *k = PIT_COMMON_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); kpc->parent_realize = dc->realize; dc->realize = kvm_pit_realizefn; k->set_channel_gate = kvm_pit_set_gate; k->get_channel_info = kvm_pit_get_channel_info; k->pre_save = kvm_pit_get; k->post_load = kvm_pit_put; dc->reset = kvm_pit_reset; dc->props = kvm_pit_properties; } static const TypeInfo kvm_pit_info = { .name = TYPE_KVM_I8254, .parent = TYPE_PIT_COMMON, .instance_size = sizeof(KVMPITState), .class_init = kvm_pit_class_init, .class_size = sizeof(KVMPITClass), }; static void kvm_pit_register(void) { type_register_static(&kvm_pit_info); } type_init(kvm_pit_register)
static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend, Error **errp) { const char *host = qemu_opt_get(opts, "host"); const char *port = qemu_opt_get(opts, "port"); const char *localaddr = qemu_opt_get(opts, "localaddr"); const char *localport = qemu_opt_get(opts, "localport"); bool has_local = false; SocketAddress *addr; ChardevUdp *udp; backend->type = CHARDEV_BACKEND_KIND_UDP; if (host == NULL || strlen(host) == 0) { host = "localhost"; } if (port == NULL || strlen(port) == 0) { error_setg(errp, "chardev: udp: remote port not specified"); return; } if (localport == NULL || strlen(localport) == 0) { localport = "0"; } else { has_local = true; } if (localaddr == NULL || strlen(localaddr) == 0) { localaddr = ""; } else { has_local = true; } udp = backend->u.udp.data = g_new0(ChardevUdp, 1); qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp)); addr = g_new0(SocketAddress, 1); addr->type = SOCKET_ADDRESS_KIND_INET; addr->u.inet.data = g_new(InetSocketAddress, 1); *addr->u.inet.data = (InetSocketAddress) { .host = g_strdup(host), .port = g_strdup(port), .has_ipv4 = qemu_opt_get(opts, "ipv4"), .ipv4 = qemu_opt_get_bool(opts, "ipv4", 0), .has_ipv6 = qemu_opt_get(opts, "ipv6"), .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0), }; udp->remote = addr; if (has_local) { udp->has_local = true; addr = g_new0(SocketAddress, 1); addr->type = SOCKET_ADDRESS_KIND_INET; addr->u.inet.data = g_new(InetSocketAddress, 1); *addr->u.inet.data = (InetSocketAddress) { .host = g_strdup(localaddr), .port = g_strdup(localport), }; udp->local = addr; } } static void qmp_chardev_open_udp(Chardev *chr, ChardevBackend *backend, bool *be_opened, Error **errp) { ChardevUdp *udp = backend->u.udp.data; QIOChannelSocket *sioc = qio_channel_socket_new(); char *name; UdpChardev *s = UDP_CHARDEV(chr); if (qio_channel_socket_dgram_sync(sioc, udp->local, udp->remote, errp) < 0) { object_unref(OBJECT(sioc)); return; } name = g_strdup_printf("chardev-udp-%s", chr->label); qio_channel_set_name(QIO_CHANNEL(sioc), name); g_free(name); s->ioc = QIO_CHANNEL(sioc); /* be isn't opened until we get a connection */ *be_opened = false; }
MigrationState *migrate_get_current(void) { static MigrationState current_migration = { .state = MIG_STATE_NONE, .bandwidth_limit = MAX_THROTTLE, .xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE, .mbps = -1, }; return ¤t_migration; } void qemu_start_incoming_migration(const char *uri, Error **errp) { const char *p; if (strstart(uri, "tcp:", &p)) tcp_start_incoming_migration(p, errp); #ifdef CONFIG_RDMA else if (strstart(uri, "rdma:", &p)) rdma_start_incoming_migration(p, errp); #endif #if !defined(WIN32) else if (strstart(uri, "exec:", &p)) exec_start_incoming_migration(p, errp); else if (strstart(uri, "unix:", &p)) unix_start_incoming_migration(p, errp); else if (strstart(uri, "fd:", &p)) fd_start_incoming_migration(p, errp); #endif else { error_setg(errp, "unknown migration protocol: %s", uri); } } static void process_incoming_migration_co(void *opaque) { QEMUFile *f = opaque; Error *local_err = NULL; int ret; ret = qemu_loadvm_state(f); qemu_fclose(f); free_xbzrle_decoded_buf(); if (ret < 0) { error_report("load of migration failed: %s", strerror(-ret)); exit(EXIT_FAILURE); } qemu_announce_self(); /* Make sure all file formats flush their mutable metadata */ bdrv_invalidate_cache_all(&local_err); if (local_err) { qerror_report_err(local_err); error_free(local_err); exit(EXIT_FAILURE); } if (autostart) { vm_start(); } else { runstate_set(RUN_STATE_PAUSED); } }
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) { struct addrinfo ai,*res,*e; const char *addr; char port[33]; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int slisten, rc, to, port_min, port_max, p; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; if ((qemu_opt_get(opts, "host") == NULL) || (qemu_opt_get(opts, "port") == NULL)) { error_setg(errp, "host and/or port not specified"); return -1; } pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port")); addr = qemu_opt_get(opts, "host"); to = qemu_opt_get_number(opts, "to", 0); if (qemu_opt_get_bool(opts, "ipv4", 0)) ai.ai_family = PF_INET; if (qemu_opt_get_bool(opts, "ipv6", 0)) ai.ai_family = PF_INET6; /* lookup */ if (port_offset) snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); if (rc != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); return -1; } /* create socket + bind */ for (e = res; e != NULL; e = e->ai_next) { getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV); slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (slisten < 0) { if (!e->ai_next) { error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); } continue; } setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); #ifdef IPV6_V6ONLY if (e->ai_family == PF_INET6) { /* listen on both ipv4 and ipv6 */ setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off, sizeof(off)); } #endif port_min = inet_getport(e); port_max = to ? to + port_offset : port_min; for (p = port_min; p <= port_max; p++) { inet_setport(e, p); if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { goto listen; } if (p == port_max) { if (!e->ai_next) { error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); } } } closesocket(slisten); } freeaddrinfo(res); return -1; listen: if (listen(slisten,1) != 0) { error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED); closesocket(slisten); freeaddrinfo(res); return -1; } snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset); qemu_opt_set(opts, "host", uaddr); qemu_opt_set(opts, "port", uport); qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off"); qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off"); freeaddrinfo(res); return slisten; }
/* compatibility wrapper */ static InetSocketAddress *inet_parse(const char *str, Error **errp) { InetSocketAddress *addr; const char *optstr, *h; char host[64]; char port[33]; int to; int pos; addr = g_new0(InetSocketAddress, 1); /* parse address */ if (str[0] == ':') { /* no host given */ host[0] = '\0'; if (1 != sscanf(str, ":%32[^,]%n", port, &pos)) { error_setg(errp, "error parsing port in address '%s'", str); goto fail; } } else if (str[0] == '[') { /* IPv6 addr */ if (2 != sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos)) { error_setg(errp, "error parsing IPv6 address '%s'", str); goto fail; } addr->ipv6 = addr->has_ipv6 = true; } else if (qemu_isdigit(str[0])) { /* IPv4 addr */ if (2 != sscanf(str, "%64[0-9.]:%32[^,]%n", host, port, &pos)) { error_setg(errp, "error parsing IPv4 address '%s'", str); goto fail; } addr->ipv4 = addr->has_ipv4 = true; } else { /* hostname */ if (2 != sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos)) { error_setg(errp, "error parsing address '%s'", str); goto fail; } } addr->host = g_strdup(host); addr->port = g_strdup(port); /* parse options */ optstr = str + pos; h = strstr(optstr, ",to="); if (h) { h += 4; if (sscanf(h, "%d%n", &to, &pos) != 1 || (h[pos] != '\0' && h[pos] != ',')) { error_setg(errp, "error parsing to= argument"); goto fail; } addr->has_to = true; addr->to = to; } if (strstr(optstr, ",ipv4")) { addr->ipv4 = addr->has_ipv4 = true; } if (strstr(optstr, ",ipv6")) { addr->ipv6 = addr->has_ipv6 = true; } return addr; fail: qapi_free_InetSocketAddress(addr); return NULL; }
/* Process another portion of the NBD_OPT_LIST reply. Set *@match if * the current reply matches @want or if the server does not support * NBD_OPT_LIST, otherwise leave @match alone. Return 0 if iteration * is complete, positive if more replies are expected, or negative * with @errp set if an unrecoverable error occurred. */ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, Error **errp) { NBDOptionReply reply; uint32_t len; uint32_t namelen; char name[NBD_MAX_NAME_SIZE + 1]; int error; if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) { return -1; } error = nbd_handle_reply_err(ioc, &reply, errp); if (error <= 0) { /* The server did not support NBD_OPT_LIST, so set *match on * the assumption that any name will be accepted. */ *match = true; return error; } len = reply.length; if (reply.type == NBD_REP_ACK) { if (len != 0) { error_setg(errp, "length too long for option end"); nbd_send_opt_abort(ioc); return -1; } return 0; } else if (reply.type != NBD_REP_SERVER) { error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x", reply.type, NBD_REP_SERVER); nbd_send_opt_abort(ioc); return -1; } if (len < sizeof(namelen) || len > NBD_MAX_BUFFER_SIZE) { error_setg(errp, "incorrect option length %" PRIu32, len); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &namelen, sizeof(namelen), errp) < 0) { error_prepend(errp, "failed to read option name length: "); nbd_send_opt_abort(ioc); return -1; } namelen = be32_to_cpu(namelen); len -= sizeof(namelen); if (len < namelen) { error_setg(errp, "incorrect option name length"); nbd_send_opt_abort(ioc); return -1; } if (namelen != strlen(want)) { if (nbd_drop(ioc, len, errp) < 0) { error_prepend(errp, "failed to skip export name with wrong length: "); nbd_send_opt_abort(ioc); return -1; } return 1; } assert(namelen < sizeof(name)); if (nbd_read(ioc, name, namelen, errp) < 0) { error_prepend(errp, "failed to read export name: "); nbd_send_opt_abort(ioc); return -1; } name[namelen] = '\0'; len -= namelen; if (nbd_drop(ioc, len, errp) < 0) { error_prepend(errp, "failed to read export description: "); nbd_send_opt_abort(ioc); return -1; } if (!strcmp(name, want)) { *match = true; } return 1; }
/* Returns -1 if NBD_OPT_GO proves the export @wantname cannot be * used, 0 if NBD_OPT_GO is unsupported (fall back to NBD_OPT_LIST and * NBD_OPT_EXPORT_NAME in that case), and > 0 if the export is good to * go (with @info populated). */ static int nbd_opt_go(QIOChannel *ioc, const char *wantname, NBDExportInfo *info, Error **errp) { NBDOptionReply reply; uint32_t len = strlen(wantname); uint16_t type; int error; char *buf; /* The protocol requires that the server send NBD_INFO_EXPORT with * a non-zero flags (at least NBD_FLAG_HAS_FLAGS must be set); so * flags still 0 is a witness of a broken server. */ info->flags = 0; trace_nbd_opt_go_start(wantname); buf = g_malloc(4 + len + 2 + 2 * info->request_sizes + 1); stl_be_p(buf, len); memcpy(buf + 4, wantname, len); /* At most one request, everything else up to server */ stw_be_p(buf + 4 + len, info->request_sizes); if (info->request_sizes) { stw_be_p(buf + 4 + len + 2, NBD_INFO_BLOCK_SIZE); } error = nbd_send_option_request(ioc, NBD_OPT_GO, 4 + len + 2 + 2 * info->request_sizes, buf, errp); g_free(buf); if (error < 0) { return -1; } while (1) { if (nbd_receive_option_reply(ioc, NBD_OPT_GO, &reply, errp) < 0) { return -1; } error = nbd_handle_reply_err(ioc, &reply, errp); if (error <= 0) { return error; } len = reply.length; if (reply.type == NBD_REP_ACK) { /* Server is done sending info and moved into transmission phase, but make sure it sent flags */ if (len) { error_setg(errp, "server sent invalid NBD_REP_ACK"); return -1; } if (!info->flags) { error_setg(errp, "broken server omitted NBD_INFO_EXPORT"); return -1; } trace_nbd_opt_go_success(); return 1; } if (reply.type != NBD_REP_INFO) { error_setg(errp, "unexpected reply type %" PRIu32 " (%s), expected %u", reply.type, nbd_rep_lookup(reply.type), NBD_REP_INFO); nbd_send_opt_abort(ioc); return -1; } if (len < sizeof(type)) { error_setg(errp, "NBD_REP_INFO length %" PRIu32 " is too short", len); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &type, sizeof(type), errp) < 0) { error_prepend(errp, "failed to read info type: "); nbd_send_opt_abort(ioc); return -1; } len -= sizeof(type); be16_to_cpus(&type); switch (type) { case NBD_INFO_EXPORT: if (len != sizeof(info->size) + sizeof(info->flags)) { error_setg(errp, "remaining export info len %" PRIu32 " is unexpected size", len); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { error_prepend(errp, "failed to read info size: "); nbd_send_opt_abort(ioc); return -1; } be64_to_cpus(&info->size); if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) { error_prepend(errp, "failed to read info flags: "); nbd_send_opt_abort(ioc); return -1; } be16_to_cpus(&info->flags); trace_nbd_receive_negotiate_size_flags(info->size, info->flags); break; case NBD_INFO_BLOCK_SIZE: if (len != sizeof(info->min_block) * 3) { error_setg(errp, "remaining export info len %" PRIu32 " is unexpected size", len); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &info->min_block, sizeof(info->min_block), errp) < 0) { error_prepend(errp, "failed to read info minimum block size: "); nbd_send_opt_abort(ioc); return -1; } be32_to_cpus(&info->min_block); if (!is_power_of_2(info->min_block)) { error_setg(errp, "server minimum block size %" PRId32 "is not a power of two", info->min_block); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &info->opt_block, sizeof(info->opt_block), errp) < 0) { error_prepend(errp, "failed to read info preferred block size: "); nbd_send_opt_abort(ioc); return -1; } be32_to_cpus(&info->opt_block); if (!is_power_of_2(info->opt_block) || info->opt_block < info->min_block) { error_setg(errp, "server preferred block size %" PRId32 "is not valid", info->opt_block); nbd_send_opt_abort(ioc); return -1; } if (nbd_read(ioc, &info->max_block, sizeof(info->max_block), errp) < 0) { error_prepend(errp, "failed to read info maximum block size: "); nbd_send_opt_abort(ioc); return -1; } be32_to_cpus(&info->max_block); trace_nbd_opt_go_info_block_size(info->min_block, info->opt_block, info->max_block); break; default: trace_nbd_opt_go_info_unknown(type, nbd_info_lookup(type)); if (nbd_drop(ioc, len, errp) < 0) { error_prepend(errp, "Failed to read info payload: "); nbd_send_opt_abort(ioc); return -1; } break; } } }
static int qcrypto_cipher_init_aes(QCryptoCipher *cipher, const uint8_t *key, size_t nkey, Error **errp) { QCryptoCipherBuiltin *ctxt; if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC && cipher->mode != QCRYPTO_CIPHER_MODE_ECB && cipher->mode != QCRYPTO_CIPHER_MODE_XTS) { error_setg(errp, "Unsupported cipher mode %s", QCryptoCipherMode_lookup[cipher->mode]); return -1; } ctxt = g_new0(QCryptoCipherBuiltin, 1); if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { if (AES_set_encrypt_key(key, nkey * 4, &ctxt->state.aes.key.enc) != 0) { error_setg(errp, "Failed to set encryption key"); goto error; } if (AES_set_decrypt_key(key, nkey * 4, &ctxt->state.aes.key.dec) != 0) { error_setg(errp, "Failed to set decryption key"); goto error; } if (AES_set_encrypt_key(key + (nkey / 2), nkey * 4, &ctxt->state.aes.key_tweak.enc) != 0) { error_setg(errp, "Failed to set encryption key"); goto error; } if (AES_set_decrypt_key(key + (nkey / 2), nkey * 4, &ctxt->state.aes.key_tweak.dec) != 0) { error_setg(errp, "Failed to set decryption key"); goto error; } } else { if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.key.enc) != 0) { error_setg(errp, "Failed to set encryption key"); goto error; } if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.key.dec) != 0) { error_setg(errp, "Failed to set decryption key"); goto error; } } ctxt->blocksize = AES_BLOCK_SIZE; ctxt->free = qcrypto_cipher_free_aes; ctxt->setiv = qcrypto_cipher_setiv_aes; ctxt->encrypt = qcrypto_cipher_encrypt_aes; ctxt->decrypt = qcrypto_cipher_decrypt_aes; cipher->opaque = ctxt; return 0; error: g_free(ctxt); return -1; }
/* If reply represents success, return 1 without further action. * If reply represents an error, consume the optional payload of * the packet on ioc. Then return 0 for unsupported (so the client * can fall back to other approaches), or -1 with errp set for other * errors. */ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, Error **errp) { char *msg = NULL; int result = -1; if (!(reply->type & (1 << 31))) { return 1; } if (reply->length) { if (reply->length > NBD_MAX_BUFFER_SIZE) { error_setg(errp, "server error %" PRIu32 " (%s) message is too long", reply->type, nbd_rep_lookup(reply->type)); goto cleanup; } msg = g_malloc(reply->length + 1); if (nbd_read(ioc, msg, reply->length, errp) < 0) { error_prepend(errp, "failed to read option error %" PRIu32 " (%s) message: ", reply->type, nbd_rep_lookup(reply->type)); goto cleanup; } msg[reply->length] = '\0'; } switch (reply->type) { case NBD_REP_ERR_UNSUP: trace_nbd_reply_err_unsup(reply->option, nbd_opt_lookup(reply->option)); result = 0; goto cleanup; case NBD_REP_ERR_POLICY: error_setg(errp, "Denied by server for option %" PRIu32 " (%s)", reply->option, nbd_opt_lookup(reply->option)); break; case NBD_REP_ERR_INVALID: error_setg(errp, "Invalid parameters for option %" PRIu32 " (%s)", reply->option, nbd_opt_lookup(reply->option)); break; case NBD_REP_ERR_PLATFORM: error_setg(errp, "Server lacks support for option %" PRIu32 " (%s)", reply->option, nbd_opt_lookup(reply->option)); break; case NBD_REP_ERR_TLS_REQD: error_setg(errp, "TLS negotiation required before option %" PRIu32 " (%s)", reply->option, nbd_opt_lookup(reply->option)); break; case NBD_REP_ERR_UNKNOWN: error_setg(errp, "Requested export not available"); break; case NBD_REP_ERR_SHUTDOWN: error_setg(errp, "Server shutting down before option %" PRIu32 " (%s)", reply->option, nbd_opt_lookup(reply->option)); break; case NBD_REP_ERR_BLOCK_SIZE_REQD: error_setg(errp, "Server requires INFO_BLOCK_SIZE for option %" PRIu32 " (%s)", reply->option, nbd_opt_lookup(reply->option)); break; default: error_setg(errp, "Unknown error code when asking for option %" PRIu32 " (%s)", reply->option, nbd_opt_lookup(reply->option)); break; } if (msg) { error_append_hint(errp, "server reported: %s\n", msg); } cleanup: g_free(msg); if (result < 0) { nbd_send_opt_abort(ioc); } return result; }
static int connect_to_ssh(BDRVSSHState *s, QDict *options, int ssh_flags, int creat_mode, Error **errp) { int r, ret; const char *host, *user, *path, *host_key_check; int port; if (!qdict_haskey(options, "host")) { ret = -EINVAL; error_setg(errp, "No hostname was specified"); goto err; } host = qdict_get_str(options, "host"); if (qdict_haskey(options, "port")) { port = qdict_get_int(options, "port"); } else { port = 22; } if (!qdict_haskey(options, "path")) { ret = -EINVAL; error_setg(errp, "No path was specified"); goto err; } path = qdict_get_str(options, "path"); if (qdict_haskey(options, "user")) { user = qdict_get_str(options, "user"); } else { user = g_get_user_name(); if (!user) { error_setg_errno(errp, errno, "Can't get user name"); ret = -errno; goto err; } } if (qdict_haskey(options, "host_key_check")) { host_key_check = qdict_get_str(options, "host_key_check"); } else { host_key_check = "yes"; } /* Construct the host:port name for inet_connect. */ g_free(s->hostport); s->hostport = g_strdup_printf("%s:%d", host, port); /* Open the socket and connect. */ s->sock = inet_connect(s->hostport, errp); if (s->sock < 0) { ret = -EIO; goto err; } /* Create SSH session. */ s->session = libssh2_session_init(); if (!s->session) { ret = -EINVAL; session_error_setg(errp, s, "failed to initialize libssh2 session"); goto err; } #if TRACE_LIBSSH2 != 0 libssh2_trace(s->session, TRACE_LIBSSH2); #endif r = libssh2_session_handshake(s->session, s->sock); if (r != 0) { ret = -EINVAL; session_error_setg(errp, s, "failed to establish SSH session"); goto err; } /* Check the remote host's key against known_hosts. */ ret = check_host_key(s, host, port, host_key_check, errp); if (ret < 0) { goto err; } /* Authenticate. */ ret = authenticate(s, user, errp); if (ret < 0) { goto err; } /* Start SFTP. */ s->sftp = libssh2_sftp_init(s->session); if (!s->sftp) { session_error_setg(errp, s, "failed to initialize sftp handle"); ret = -EINVAL; goto err; } /* Open the remote file. */ DPRINTF("opening file %s flags=0x%x creat_mode=0%o", path, ssh_flags, creat_mode); s->sftp_handle = libssh2_sftp_open(s->sftp, path, ssh_flags, creat_mode); if (!s->sftp_handle) { session_error_setg(errp, s, "failed to open remote file '%s'", path); ret = -EINVAL; goto err; } r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs); if (r < 0) { sftp_error_setg(errp, s, "failed to read file attributes"); return -EINVAL; } /* Delete the options we've used; any not deleted will cause the * block layer to give an error about unused options. */ qdict_del(options, "host"); qdict_del(options, "port"); qdict_del(options, "user"); qdict_del(options, "path"); qdict_del(options, "host_key_check"); return 0; err: if (s->sftp_handle) { libssh2_sftp_close(s->sftp_handle); } s->sftp_handle = NULL; if (s->sftp) { libssh2_sftp_shutdown(s->sftp); } s->sftp = NULL; if (s->session) { libssh2_session_disconnect(s->session, "from qemu ssh client: " "error opening connection"); libssh2_session_free(s->session); } s->session = NULL; return ret; }
static int authenticate(BDRVSSHState *s, const char *user, Error **errp) { int r, ret; const char *userauthlist; LIBSSH2_AGENT *agent = NULL; struct libssh2_agent_publickey *identity; struct libssh2_agent_publickey *prev_identity = NULL; userauthlist = libssh2_userauth_list(s->session, user, strlen(user)); if (strstr(userauthlist, "publickey") == NULL) { ret = -EPERM; error_setg(errp, "remote server does not support \"publickey\" authentication"); goto out; } /* Connect to ssh-agent and try each identity in turn. */ agent = libssh2_agent_init(s->session); if (!agent) { ret = -EINVAL; session_error_setg(errp, s, "failed to initialize ssh-agent support"); goto out; } if (libssh2_agent_connect(agent)) { ret = -ECONNREFUSED; session_error_setg(errp, s, "failed to connect to ssh-agent"); goto out; } if (libssh2_agent_list_identities(agent)) { ret = -EINVAL; session_error_setg(errp, s, "failed requesting identities from ssh-agent"); goto out; } for(;;) { r = libssh2_agent_get_identity(agent, &identity, prev_identity); if (r == 1) { /* end of list */ break; } if (r < 0) { ret = -EINVAL; session_error_setg(errp, s, "failed to obtain identity from ssh-agent"); goto out; } r = libssh2_agent_userauth(agent, user, identity); if (r == 0) { /* Authenticated! */ ret = 0; goto out; } /* Failed to authenticate with this identity, try the next one. */ prev_identity = identity; } ret = -EPERM; error_setg(errp, "failed to authenticate using publickey authentication " "and the identities held by your ssh-agent"); out: if (agent != NULL) { /* Note: libssh2 implementation implicitly calls * libssh2_agent_disconnect if necessary. */ libssh2_agent_free(agent); } return ret; }
static int parse_uri(const char *filename, QDict *options, Error **errp) { URI *uri = NULL; QueryParams *qp; int i; uri = uri_parse(filename); if (!uri) { return -EINVAL; } if (strcmp(uri->scheme, "ssh") != 0) { error_setg(errp, "URI scheme must be 'ssh'"); goto err; } if (!uri->server || strcmp(uri->server, "") == 0) { error_setg(errp, "missing hostname in URI"); goto err; } if (!uri->path || strcmp(uri->path, "") == 0) { error_setg(errp, "missing remote path in URI"); goto err; } qp = query_params_parse(uri->query); if (!qp) { error_setg(errp, "could not parse query parameters"); goto err; } if(uri->user && strcmp(uri->user, "") != 0) { qdict_put(options, "user", qstring_from_str(uri->user)); } qdict_put(options, "host", qstring_from_str(uri->server)); if (uri->port) { qdict_put(options, "port", qint_from_int(uri->port)); } qdict_put(options, "path", qstring_from_str(uri->path)); /* Pick out any query parameters that we understand, and ignore * the rest. */ for (i = 0; i < qp->n; ++i) { if (strcmp(qp->p[i].name, "host_key_check") == 0) { qdict_put(options, "host_key_check", qstring_from_str(qp->p[i].value)); } } query_params_free(qp); uri_free(uri); return 0; err: if (uri) { uri_free(uri); } return -EINVAL; }
static int qcrypto_tls_session_check_certificate(QCryptoTLSSession *session, Error **errp) { int ret; unsigned int status; const gnutls_datum_t *certs; unsigned int nCerts, i; time_t now; gnutls_x509_crt_t cert = NULL; now = time(NULL); if (now == ((time_t)-1)) { error_setg_errno(errp, errno, "Cannot get current time"); return -1; } ret = gnutls_certificate_verify_peers2(session->handle, &status); if (ret < 0) { error_setg(errp, "Verify failed: %s", gnutls_strerror(ret)); return -1; } if (status != 0) { const char *reason = "Invalid certificate"; if (status & GNUTLS_CERT_INVALID) { reason = "The certificate is not trusted"; } if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { reason = "The certificate hasn't got a known issuer"; } if (status & GNUTLS_CERT_REVOKED) { reason = "The certificate has been revoked"; } if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { reason = "The certificate uses an insecure algorithm"; } error_setg(errp, "%s", reason); return -1; } certs = gnutls_certificate_get_peers(session->handle, &nCerts); if (!certs) { error_setg(errp, "No certificate peers"); return -1; } for (i = 0; i < nCerts; i++) { ret = gnutls_x509_crt_init(&cert); if (ret < 0) { error_setg(errp, "Cannot initialize certificate: %s", gnutls_strerror(ret)); return -1; } ret = gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER); if (ret < 0) { error_setg(errp, "Cannot import certificate: %s", gnutls_strerror(ret)); goto error; } if (gnutls_x509_crt_get_expiration_time(cert) < now) { error_setg(errp, "The certificate has expired"); goto error; } if (gnutls_x509_crt_get_activation_time(cert) > now) { error_setg(errp, "The certificate is not yet activated"); goto error; } if (gnutls_x509_crt_get_activation_time(cert) > now) { error_setg(errp, "The certificate is not yet activated"); goto error; } if (i == 0) { size_t dnameSize = 1024; session->peername = g_malloc(dnameSize); requery: ret = gnutls_x509_crt_get_dn(cert, session->peername, &dnameSize); if (ret < 0) { if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { session->peername = g_realloc(session->peername, dnameSize); goto requery; } error_setg(errp, "Cannot get client distinguished name: %s", gnutls_strerror(ret)); goto error; } if (session->aclname) { qemu_acl *acl = qemu_acl_find(session->aclname); int allow; if (!acl) { error_setg(errp, "Cannot find ACL %s", session->aclname); goto error; } allow = qemu_acl_party_is_allowed(acl, session->peername); if (!allow) { error_setg(errp, "TLS x509 ACL check for %s is denied", session->peername); goto error; } } if (session->hostname) { if (!gnutls_x509_crt_check_hostname(cert, session->hostname)) { error_setg(errp, "Certificate does not match the hostname %s", session->hostname); goto error; } } } gnutls_x509_crt_deinit(cert); } return 0; error: gnutls_x509_crt_deinit(cert); return -1; }
int nbd_receive_negotiate(QIOChannel *ioc, const char *name, QCryptoTLSCreds *tlscreds, const char *hostname, QIOChannel **outioc, NBDExportInfo *info, Error **errp) { char buf[256]; uint64_t magic; int rc; bool zeroes = true; bool structured_reply = info->structured_reply; trace_nbd_receive_negotiate(tlscreds, hostname ? hostname : "<null>"); info->structured_reply = false; rc = -EINVAL; if (outioc) { *outioc = NULL; } if (tlscreds && !outioc) { error_setg(errp, "Output I/O channel required for TLS"); goto fail; } if (nbd_read(ioc, buf, 8, errp) < 0) { error_prepend(errp, "Failed to read data: "); goto fail; } buf[8] = '\0'; if (strlen(buf) == 0) { error_setg(errp, "Server connection closed unexpectedly"); goto fail; } magic = ldq_be_p(buf); trace_nbd_receive_negotiate_magic(magic); if (memcmp(buf, "NBDMAGIC", 8) != 0) { error_setg(errp, "Invalid magic received"); goto fail; } if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) { error_prepend(errp, "Failed to read magic: "); goto fail; } magic = be64_to_cpu(magic); trace_nbd_receive_negotiate_magic(magic); if (magic == NBD_OPTS_MAGIC) { uint32_t clientflags = 0; uint16_t globalflags; bool fixedNewStyle = false; if (nbd_read(ioc, &globalflags, sizeof(globalflags), errp) < 0) { error_prepend(errp, "Failed to read server flags: "); goto fail; } globalflags = be16_to_cpu(globalflags); trace_nbd_receive_negotiate_server_flags(globalflags); if (globalflags & NBD_FLAG_FIXED_NEWSTYLE) { fixedNewStyle = true; clientflags |= NBD_FLAG_C_FIXED_NEWSTYLE; } if (globalflags & NBD_FLAG_NO_ZEROES) { zeroes = false; clientflags |= NBD_FLAG_C_NO_ZEROES; } /* client requested flags */ clientflags = cpu_to_be32(clientflags); if (nbd_write(ioc, &clientflags, sizeof(clientflags), errp) < 0) { error_prepend(errp, "Failed to send clientflags field: "); goto fail; } if (tlscreds) { if (fixedNewStyle) { *outioc = nbd_receive_starttls(ioc, tlscreds, hostname, errp); if (!*outioc) { goto fail; } ioc = *outioc; } else { error_setg(errp, "Server does not support STARTTLS"); goto fail; } } if (!name) { trace_nbd_receive_negotiate_default_name(); name = ""; } if (fixedNewStyle) { int result; if (structured_reply) { result = nbd_request_simple_option(ioc, NBD_OPT_STRUCTURED_REPLY, errp); if (result < 0) { goto fail; } info->structured_reply = result == 1; } /* Try NBD_OPT_GO first - if it works, we are done (it * also gives us a good message if the server requires * TLS). If it is not available, fall back to * NBD_OPT_LIST for nicer error messages about a missing * export, then use NBD_OPT_EXPORT_NAME. */ result = nbd_opt_go(ioc, name, info, errp); if (result < 0) { goto fail; } if (result > 0) { return 0; } /* Check our desired export is present in the * server export list. Since NBD_OPT_EXPORT_NAME * cannot return an error message, running this * query gives us better error reporting if the * export name is not available. */ if (nbd_receive_query_exports(ioc, name, errp) < 0) { goto fail; } } /* write the export name request */ if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, name, errp) < 0) { goto fail; } /* Read the response */ if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { error_prepend(errp, "Failed to read export length: "); goto fail; } be64_to_cpus(&info->size); if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) { error_prepend(errp, "Failed to read export flags: "); goto fail; } be16_to_cpus(&info->flags); } else if (magic == NBD_CLIENT_MAGIC) { uint32_t oldflags; if (name) { error_setg(errp, "Server does not support export names"); goto fail; } if (tlscreds) { error_setg(errp, "Server does not support STARTTLS"); goto fail; } if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) { error_prepend(errp, "Failed to read export length: "); goto fail; } be64_to_cpus(&info->size); if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { error_prepend(errp, "Failed to read export flags: "); goto fail; } be32_to_cpus(&oldflags); if (oldflags & ~0xffff) { error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); goto fail; } info->flags = oldflags; } else { error_setg(errp, "Bad magic received"); goto fail; } trace_nbd_receive_negotiate_size_flags(info->size, info->flags); if (zeroes && nbd_drop(ioc, 124, errp) < 0) { error_prepend(errp, "Failed to read reserved block: "); goto fail; } rc = 0; fail: return rc; }
QCryptoTLSSession * qcrypto_tls_session_new(QCryptoTLSCreds *creds, const char *hostname, const char *aclname, QCryptoTLSCredsEndpoint endpoint, Error **errp) { QCryptoTLSSession *session; int ret; session = g_new0(QCryptoTLSSession, 1); trace_qcrypto_tls_session_new( session, creds, hostname ? hostname : "<none>", aclname ? aclname : "<none>", endpoint); if (hostname) { session->hostname = g_strdup(hostname); } if (aclname) { session->aclname = g_strdup(aclname); } session->creds = creds; object_ref(OBJECT(creds)); if (creds->endpoint != endpoint) { error_setg(errp, "Credentials endpoint doesn't match session"); goto error; } if (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { ret = gnutls_init(&session->handle, GNUTLS_SERVER); } else { ret = gnutls_init(&session->handle, GNUTLS_CLIENT); } if (ret < 0) { error_setg(errp, "Cannot initialize TLS session: %s", gnutls_strerror(ret)); goto error; } if (object_dynamic_cast(OBJECT(creds), TYPE_QCRYPTO_TLS_CREDS_ANON)) { QCryptoTLSCredsAnon *acreds = QCRYPTO_TLS_CREDS_ANON(creds); char *prio; if (creds->priority != NULL) { prio = g_strdup_printf("%s:+ANON-DH", creds->priority); } else { prio = g_strdup(CONFIG_TLS_PRIORITY ":+ANON-DH"); } ret = gnutls_priority_set_direct(session->handle, prio, NULL); if (ret < 0) { error_setg(errp, "Unable to set TLS session priority %s: %s", prio, gnutls_strerror(ret)); g_free(prio); goto error; } g_free(prio); if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { ret = gnutls_credentials_set(session->handle, GNUTLS_CRD_ANON, acreds->data.server); } else { ret = gnutls_credentials_set(session->handle, GNUTLS_CRD_ANON, acreds->data.client); } if (ret < 0) { error_setg(errp, "Cannot set session credentials: %s", gnutls_strerror(ret)); goto error; } } else if (object_dynamic_cast(OBJECT(creds), TYPE_QCRYPTO_TLS_CREDS_X509)) { QCryptoTLSCredsX509 *tcreds = QCRYPTO_TLS_CREDS_X509(creds); const char *prio = creds->priority; if (!prio) { prio = CONFIG_TLS_PRIORITY; } ret = gnutls_priority_set_direct(session->handle, prio, NULL); if (ret < 0) { error_setg(errp, "Cannot set default TLS session priority %s: %s", prio, gnutls_strerror(ret)); goto error; } ret = gnutls_credentials_set(session->handle, GNUTLS_CRD_CERTIFICATE, tcreds->data); if (ret < 0) { error_setg(errp, "Cannot set session credentials: %s", gnutls_strerror(ret)); goto error; } if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { /* This requests, but does not enforce a client cert. * The cert checking code later does enforcement */ gnutls_certificate_server_set_request(session->handle, GNUTLS_CERT_REQUEST); } } else { error_setg(errp, "Unsupported TLS credentials type %s", object_get_typename(OBJECT(creds))); goto error; } gnutls_transport_set_ptr(session->handle, session); gnutls_transport_set_push_function(session->handle, qcrypto_tls_session_push); gnutls_transport_set_pull_function(session->handle, qcrypto_tls_session_pull); return session; error: qcrypto_tls_session_free(session); return NULL; }
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info, Error **errp) { unsigned long sector_size = MAX(BDRV_SECTOR_SIZE, info->min_block); unsigned long sectors = info->size / sector_size; /* FIXME: Once the kernel module is patched to honor block sizes, * and to advertise that fact to user space, we should update the * hand-off to the kernel to use any block sizes we learned. */ assert(!info->request_sizes); if (info->size / sector_size != sectors) { error_setg(errp, "Export size %" PRIu64 " too large for 32-bit kernel", info->size); return -E2BIG; } trace_nbd_init_set_socket(); if (ioctl(fd, NBD_SET_SOCK, (unsigned long) sioc->fd) < 0) { int serrno = errno; error_setg(errp, "Failed to set NBD socket"); return -serrno; } trace_nbd_init_set_block_size(sector_size); if (ioctl(fd, NBD_SET_BLKSIZE, sector_size) < 0) { int serrno = errno; error_setg(errp, "Failed setting NBD block size"); return -serrno; } trace_nbd_init_set_size(sectors); if (info->size % sector_size) { trace_nbd_init_trailing_bytes(info->size % sector_size); } if (ioctl(fd, NBD_SET_SIZE_BLOCKS, sectors) < 0) { int serrno = errno; error_setg(errp, "Failed setting size (in blocks)"); return -serrno; } if (ioctl(fd, NBD_SET_FLAGS, (unsigned long) info->flags) < 0) { if (errno == ENOTTY) { int read_only = (info->flags & NBD_FLAG_READ_ONLY) != 0; trace_nbd_init_set_readonly(); if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) { int serrno = errno; error_setg(errp, "Failed setting read-only attribute"); return -serrno; } } else { int serrno = errno; error_setg(errp, "Failed setting flags"); return -serrno; } } trace_nbd_init_finish(); return 0; }
int inet_dgram_opts(QemuOpts *opts, Error **errp) { struct addrinfo ai, *peer = NULL, *local = NULL; const char *addr; const char *port; int sock = -1, rc; /* lookup peer addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_DGRAM; addr = qemu_opt_get(opts, "host"); port = qemu_opt_get(opts, "port"); if (addr == NULL || strlen(addr) == 0) { addr = "localhost"; } if (port == NULL || strlen(port) == 0) { error_setg(errp, "remote port not specified"); return -1; } if (qemu_opt_get_bool(opts, "ipv4", 0)) ai.ai_family = PF_INET; if (qemu_opt_get_bool(opts, "ipv6", 0)) ai.ai_family = PF_INET6; if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); return -1; } /* lookup local addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; ai.ai_family = peer->ai_family; ai.ai_socktype = SOCK_DGRAM; addr = qemu_opt_get(opts, "localaddr"); port = qemu_opt_get(opts, "localport"); if (addr == NULL || strlen(addr) == 0) { addr = NULL; } if (!port || strlen(port) == 0) port = "0"; if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); goto err; } /* create socket */ sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); if (sock < 0) { error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); goto err; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); /* bind socket */ if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); goto err; } /* connect to peer */ if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED); goto err; } freeaddrinfo(local); freeaddrinfo(peer); return sock; err: if (-1 != sock) closesocket(sock); if (local) freeaddrinfo(local); if (peer) freeaddrinfo(peer); return -1; }
int nbd_init(int fd, QIOChannelSocket *ioc, NBDExportInfo *info, Error **errp) { error_setg(errp, "nbd_init is only supported on Linux"); return -ENOTSUP; }
int unix_listen_opts(QemuOpts *opts, Error **errp) { error_setg(errp, "unix sockets are not available on windows"); errno = ENOTSUP; return -1; }
/** * Deal with a quirk of dm-crypt usage of ESSIV. * * When calculating ESSIV IVs, the cipher length used by ESSIV * may be different from the cipher length used for the block * encryption, becauses dm-crypt uses the hash digest length * as the key size. ie, if you have AES 128 as the block cipher * and SHA 256 as ESSIV hash, then ESSIV will use AES 256 as * the cipher since that gets a key length matching the digest * size, not AES 128 with truncated digest as might be imagined */ static QCryptoCipherAlgorithm qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgorithm cipher, QCryptoHashAlgorithm hash, Error **errp) { size_t digestlen = qcrypto_hash_digest_len(hash); size_t keylen = qcrypto_cipher_get_key_len(cipher); if (digestlen == keylen) { return cipher; } switch (cipher) { case QCRYPTO_CIPHER_ALG_AES_128: case QCRYPTO_CIPHER_ALG_AES_192: case QCRYPTO_CIPHER_ALG_AES_256: if (digestlen == qcrypto_cipher_get_key_len( QCRYPTO_CIPHER_ALG_AES_128)) { return QCRYPTO_CIPHER_ALG_AES_128; } else if (digestlen == qcrypto_cipher_get_key_len( QCRYPTO_CIPHER_ALG_AES_192)) { return QCRYPTO_CIPHER_ALG_AES_192; } else if (digestlen == qcrypto_cipher_get_key_len( QCRYPTO_CIPHER_ALG_AES_256)) { return QCRYPTO_CIPHER_ALG_AES_256; } else { error_setg(errp, "No AES cipher with key size %zu available", digestlen); return 0; } break; case QCRYPTO_CIPHER_ALG_SERPENT_128: case QCRYPTO_CIPHER_ALG_SERPENT_192: case QCRYPTO_CIPHER_ALG_SERPENT_256: if (digestlen == qcrypto_cipher_get_key_len( QCRYPTO_CIPHER_ALG_SERPENT_128)) { return QCRYPTO_CIPHER_ALG_SERPENT_128; } else if (digestlen == qcrypto_cipher_get_key_len( QCRYPTO_CIPHER_ALG_SERPENT_192)) { return QCRYPTO_CIPHER_ALG_SERPENT_192; } else if (digestlen == qcrypto_cipher_get_key_len( QCRYPTO_CIPHER_ALG_SERPENT_256)) { return QCRYPTO_CIPHER_ALG_SERPENT_256; } else { error_setg(errp, "No Serpent cipher with key size %zu available", digestlen); return 0; } break; case QCRYPTO_CIPHER_ALG_TWOFISH_128: case QCRYPTO_CIPHER_ALG_TWOFISH_192: case QCRYPTO_CIPHER_ALG_TWOFISH_256: if (digestlen == qcrypto_cipher_get_key_len( QCRYPTO_CIPHER_ALG_TWOFISH_128)) { return QCRYPTO_CIPHER_ALG_TWOFISH_128; } else if (digestlen == qcrypto_cipher_get_key_len( QCRYPTO_CIPHER_ALG_TWOFISH_192)) { return QCRYPTO_CIPHER_ALG_TWOFISH_192; } else if (digestlen == qcrypto_cipher_get_key_len( QCRYPTO_CIPHER_ALG_TWOFISH_256)) { return QCRYPTO_CIPHER_ALG_TWOFISH_256; } else { error_setg(errp, "No Twofish cipher with key size %zu available", digestlen); return 0; } break; default: error_setg(errp, "Cipher %s not supported with essiv", QCryptoCipherAlgorithm_lookup[cipher]); return 0; } }
int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required, int mq_required, Error **errp) { error_setg(errp, "no tap on AIX"); return -1; }
static int qcrypto_block_luks_open(QCryptoBlock *block, QCryptoBlockOpenOptions *options, QCryptoBlockReadFunc readfunc, void *opaque, unsigned int flags, Error **errp) { QCryptoBlockLUKS *luks; Error *local_err = NULL; int ret = 0; size_t i; ssize_t rv; uint8_t *masterkey = NULL; size_t masterkeylen; char *ivgen_name, *ivhash_name; QCryptoCipherMode ciphermode; QCryptoCipherAlgorithm cipheralg; QCryptoIVGenAlgorithm ivalg; QCryptoCipherAlgorithm ivcipheralg; QCryptoHashAlgorithm hash; QCryptoHashAlgorithm ivhash; char *password = NULL; if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) { if (!options->u.luks.key_secret) { error_setg(errp, "Parameter 'key-secret' is required for cipher"); return -1; } password = qcrypto_secret_lookup_as_utf8( options->u.luks.key_secret, errp); if (!password) { return -1; } } luks = g_new0(QCryptoBlockLUKS, 1); block->opaque = luks; /* Read the entire LUKS header, minus the key material from * the underlying device */ rv = readfunc(block, 0, (uint8_t *)&luks->header, sizeof(luks->header), errp, opaque); if (rv < 0) { ret = rv; goto fail; } /* The header is always stored in big-endian format, so * convert everything to native */ be16_to_cpus(&luks->header.version); be32_to_cpus(&luks->header.payload_offset); be32_to_cpus(&luks->header.key_bytes); be32_to_cpus(&luks->header.master_key_iterations); for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { be32_to_cpus(&luks->header.key_slots[i].active); be32_to_cpus(&luks->header.key_slots[i].iterations); be32_to_cpus(&luks->header.key_slots[i].key_offset); be32_to_cpus(&luks->header.key_slots[i].stripes); } if (memcmp(luks->header.magic, qcrypto_block_luks_magic, QCRYPTO_BLOCK_LUKS_MAGIC_LEN) != 0) { error_setg(errp, "Volume is not in LUKS format"); ret = -EINVAL; goto fail; } if (luks->header.version != QCRYPTO_BLOCK_LUKS_VERSION) { error_setg(errp, "LUKS version %" PRIu32 " is not supported", luks->header.version); ret = -ENOTSUP; goto fail; } /* * The cipher_mode header contains a string that we have * to further parse, of the format * * <cipher-mode>-<iv-generator>[:<iv-hash>] * * eg cbc-essiv:sha256, cbc-plain64 */ ivgen_name = strchr(luks->header.cipher_mode, '-'); if (!ivgen_name) { ret = -EINVAL; error_setg(errp, "Unexpected cipher mode string format %s", luks->header.cipher_mode); goto fail; } *ivgen_name = '\0'; ivgen_name++; ivhash_name = strchr(ivgen_name, ':'); if (!ivhash_name) { ivhash = 0; } else { *ivhash_name = '\0'; ivhash_name++; ivhash = qcrypto_block_luks_hash_name_lookup(ivhash_name, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } } ciphermode = qcrypto_block_luks_cipher_mode_lookup(luks->header.cipher_mode, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } cipheralg = qcrypto_block_luks_cipher_name_lookup(luks->header.cipher_name, ciphermode, luks->header.key_bytes, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } hash = qcrypto_block_luks_hash_name_lookup(luks->header.hash_spec, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } ivalg = qcrypto_block_luks_ivgen_name_lookup(ivgen_name, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } if (ivalg == QCRYPTO_IVGEN_ALG_ESSIV) { ivcipheralg = qcrypto_block_luks_essiv_cipher(cipheralg, ivhash, &local_err); if (local_err) { ret = -ENOTSUP; error_propagate(errp, local_err); goto fail; } } else { ivcipheralg = cipheralg; } if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) { /* Try to find which key slot our password is valid for * and unlock the master key from that slot. */ if (qcrypto_block_luks_find_key(block, password, cipheralg, ciphermode, hash, ivalg, ivcipheralg, ivhash, &masterkey, &masterkeylen, readfunc, opaque, errp) < 0) { ret = -EACCES; goto fail; } /* We have a valid master key now, so can setup the * block device payload decryption objects */ block->kdfhash = hash; block->niv = qcrypto_cipher_get_iv_len(cipheralg, ciphermode); block->ivgen = qcrypto_ivgen_new(ivalg, ivcipheralg, ivhash, masterkey, masterkeylen, errp); if (!block->ivgen) { ret = -ENOTSUP; goto fail; } block->cipher = qcrypto_cipher_new(cipheralg, ciphermode, masterkey, masterkeylen, errp); if (!block->cipher) { ret = -ENOTSUP; goto fail; } } block->payload_offset = luks->header.payload_offset * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; g_free(masterkey); g_free(password); return 0; fail: g_free(masterkey); qcrypto_cipher_free(block->cipher); qcrypto_ivgen_free(block->ivgen); g_free(luks); g_free(password); return ret; }
static void scsi_generic_realize(SCSIDevice *s, Error **errp) { int rc; int sg_version; struct sg_scsi_id scsiid; if (!s->conf.blk) { error_setg(errp, "drive property not set"); return; } if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) { error_setg(errp, "Device doesn't support drive option werror"); return; } if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) { error_setg(errp, "Device doesn't support drive option rerror"); return; } /* check we are using a driver managing SG_IO (version 3 and after */ rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version); if (rc < 0) { error_setg(errp, "cannot get SG_IO version number: %s. " "Is this a SCSI device?", strerror(-rc)); return; } if (sg_version < 30000) { error_setg(errp, "scsi generic interface too old"); return; } /* get LUN of the /dev/sg? */ if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) { error_setg(errp, "SG_GET_SCSI_ID ioctl failed"); return; } /* define device state */ s->type = scsiid.scsi_type; DPRINTF("device type %d\n", s->type); switch (s->type) { case TYPE_TAPE: s->blocksize = get_stream_blocksize(s->conf.blk); if (s->blocksize == -1) { s->blocksize = 0; } break; /* Make a guess for block devices, we'll fix it when the guest sends. * READ CAPACITY. If they don't, they likely would assume these sizes * anyway. (TODO: they could also send MODE SENSE). */ case TYPE_ROM: case TYPE_WORM: s->blocksize = 2048; break; default: s->blocksize = 512; break; } DPRINTF("block size %d\n", s->blocksize); }
static int qcrypto_block_luks_create(QCryptoBlock *block, QCryptoBlockCreateOptions *options, QCryptoBlockInitFunc initfunc, QCryptoBlockWriteFunc writefunc, void *opaque, Error **errp) { QCryptoBlockLUKS *luks; QCryptoBlockCreateOptionsLUKS luks_opts; Error *local_err = NULL; uint8_t *masterkey = NULL; uint8_t *slotkey = NULL; uint8_t *splitkey = NULL; size_t splitkeylen = 0; size_t i; QCryptoCipher *cipher = NULL; QCryptoIVGen *ivgen = NULL; char *password; const char *cipher_alg; const char *cipher_mode; const char *ivgen_alg; const char *ivgen_hash_alg = NULL; const char *hash_alg; char *cipher_mode_spec = NULL; QCryptoCipherAlgorithm ivcipheralg = 0; memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts)); if (!luks_opts.has_cipher_alg) { luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256; } if (!luks_opts.has_cipher_mode) { luks_opts.cipher_mode = QCRYPTO_CIPHER_MODE_XTS; } if (!luks_opts.has_ivgen_alg) { luks_opts.ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64; } if (!luks_opts.has_hash_alg) { luks_opts.hash_alg = QCRYPTO_HASH_ALG_SHA256; } if (!options->u.luks.key_secret) { error_setg(errp, "Parameter 'key-secret' is required for cipher"); return -1; } password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp); if (!password) { return -1; } luks = g_new0(QCryptoBlockLUKS, 1); block->opaque = luks; memcpy(luks->header.magic, qcrypto_block_luks_magic, QCRYPTO_BLOCK_LUKS_MAGIC_LEN); /* We populate the header in native endianness initially and * then convert everything to big endian just before writing * it out to disk */ luks->header.version = QCRYPTO_BLOCK_LUKS_VERSION; if (qcrypto_block_luks_uuid_gen(luks->header.uuid, errp) < 0) { goto error; } cipher_alg = qcrypto_block_luks_cipher_alg_lookup(luks_opts.cipher_alg, errp); if (!cipher_alg) { goto error; } cipher_mode = QCryptoCipherMode_lookup[luks_opts.cipher_mode]; ivgen_alg = QCryptoIVGenAlgorithm_lookup[luks_opts.ivgen_alg]; if (luks_opts.has_ivgen_hash_alg) { ivgen_hash_alg = QCryptoHashAlgorithm_lookup[luks_opts.ivgen_hash_alg]; cipher_mode_spec = g_strdup_printf("%s-%s:%s", cipher_mode, ivgen_alg, ivgen_hash_alg); } else { cipher_mode_spec = g_strdup_printf("%s-%s", cipher_mode, ivgen_alg); } hash_alg = QCryptoHashAlgorithm_lookup[luks_opts.hash_alg]; if (strlen(cipher_alg) >= QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN) { error_setg(errp, "Cipher name '%s' is too long for LUKS header", cipher_alg); goto error; } if (strlen(cipher_mode_spec) >= QCRYPTO_BLOCK_LUKS_CIPHER_MODE_LEN) { error_setg(errp, "Cipher mode '%s' is too long for LUKS header", cipher_mode_spec); goto error; } if (strlen(hash_alg) >= QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN) { error_setg(errp, "Hash name '%s' is too long for LUKS header", hash_alg); goto error; } if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) { ivcipheralg = qcrypto_block_luks_essiv_cipher(luks_opts.cipher_alg, luks_opts.ivgen_hash_alg, &local_err); if (local_err) { error_propagate(errp, local_err); goto error; } } else { ivcipheralg = luks_opts.cipher_alg; } strcpy(luks->header.cipher_name, cipher_alg); strcpy(luks->header.cipher_mode, cipher_mode_spec); strcpy(luks->header.hash_spec, hash_alg); luks->header.key_bytes = qcrypto_cipher_get_key_len(luks_opts.cipher_alg); if (luks_opts.cipher_mode == QCRYPTO_CIPHER_MODE_XTS) { luks->header.key_bytes *= 2; } /* Generate the salt used for hashing the master key * with PBKDF later */ if (qcrypto_random_bytes(luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, errp) < 0) { goto error; } /* Generate random master key */ masterkey = g_new0(uint8_t, luks->header.key_bytes); if (qcrypto_random_bytes(masterkey, luks->header.key_bytes, errp) < 0) { goto error; } /* Setup the block device payload encryption objects */ block->cipher = qcrypto_cipher_new(luks_opts.cipher_alg, luks_opts.cipher_mode, masterkey, luks->header.key_bytes, errp); if (!block->cipher) { goto error; } block->kdfhash = luks_opts.hash_alg; block->niv = qcrypto_cipher_get_iv_len(luks_opts.cipher_alg, luks_opts.cipher_mode); block->ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg, ivcipheralg, luks_opts.ivgen_hash_alg, masterkey, luks->header.key_bytes, errp); if (!block->ivgen) { goto error; } /* Determine how many iterations we need to hash the master * key, in order to have 1 second of compute time used */ luks->header.master_key_iterations = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg, masterkey, luks->header.key_bytes, luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, &local_err); if (local_err) { error_propagate(errp, local_err); goto error; } /* Why /= 8 ? That matches cryptsetup, but there's no * explanation why they chose /= 8... Probably so that * if all 8 keyslots are active we only spend 1 second * in total time to check all keys */ luks->header.master_key_iterations /= 8; luks->header.master_key_iterations = MAX( luks->header.master_key_iterations, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS); /* Hash the master key, saving the result in the LUKS * header. This hash is used when opening the encrypted * device to verify that the user password unlocked a * valid master key */ if (qcrypto_pbkdf2(luks_opts.hash_alg, masterkey, luks->header.key_bytes, luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, luks->header.master_key_iterations, luks->header.master_key_digest, QCRYPTO_BLOCK_LUKS_DIGEST_LEN, errp) < 0) { goto error; } /* Although LUKS has multiple key slots, we're just going * to use the first key slot */ splitkeylen = luks->header.key_bytes * QCRYPTO_BLOCK_LUKS_STRIPES; for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { luks->header.key_slots[i].active = i == 0 ? QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED : QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED; luks->header.key_slots[i].stripes = QCRYPTO_BLOCK_LUKS_STRIPES; /* This calculation doesn't match that shown in the spec, * but instead follows the cryptsetup implementation. */ luks->header.key_slots[i].key_offset = (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) + (ROUND_UP(((splitkeylen + (QCRYPTO_BLOCK_LUKS_SECTOR_SIZE - 1)) / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE), (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * i); } if (qcrypto_random_bytes(luks->header.key_slots[0].salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, errp) < 0) { goto error; } /* Again we determine how many iterations are required to * hash the user password while consuming 1 second of compute * time */ luks->header.key_slots[0].iterations = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg, (uint8_t *)password, strlen(password), luks->header.key_slots[0].salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, &local_err); if (local_err) { error_propagate(errp, local_err); goto error; } /* Why /= 2 ? That matches cryptsetup, but there's no * explanation why they chose /= 2... */ luks->header.key_slots[0].iterations /= 2; luks->header.key_slots[0].iterations = MAX( luks->header.key_slots[0].iterations, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS); /* Generate a key that we'll use to encrypt the master * key, from the user's password */ slotkey = g_new0(uint8_t, luks->header.key_bytes); if (qcrypto_pbkdf2(luks_opts.hash_alg, (uint8_t *)password, strlen(password), luks->header.key_slots[0].salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, luks->header.key_slots[0].iterations, slotkey, luks->header.key_bytes, errp) < 0) { goto error; } /* Setup the encryption objects needed to encrypt the * master key material */ cipher = qcrypto_cipher_new(luks_opts.cipher_alg, luks_opts.cipher_mode, slotkey, luks->header.key_bytes, errp); if (!cipher) { goto error; } ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg, ivcipheralg, luks_opts.ivgen_hash_alg, slotkey, luks->header.key_bytes, errp); if (!ivgen) { goto error; } /* Before storing the master key, we need to vastly * increase its size, as protection against forensic * disk data recovery */ splitkey = g_new0(uint8_t, splitkeylen); if (qcrypto_afsplit_encode(luks_opts.hash_alg, luks->header.key_bytes, luks->header.key_slots[0].stripes, masterkey, splitkey, errp) < 0) { goto error; } /* Now we encrypt the split master key with the key generated * from the user's password, before storing it */ if (qcrypto_block_encrypt_helper(cipher, block->niv, ivgen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, 0, splitkey, splitkeylen, errp) < 0) { goto error; } /* The total size of the LUKS headers is the partition header + key * slot headers, rounded up to the nearest sector, combined with * the size of each master key material region, also rounded up * to the nearest sector */ luks->header.payload_offset = (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) + (ROUND_UP(((splitkeylen + (QCRYPTO_BLOCK_LUKS_SECTOR_SIZE - 1)) / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE), (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS); block->payload_offset = luks->header.payload_offset * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; /* Reserve header space to match payload offset */ initfunc(block, block->payload_offset, &local_err, opaque); if (local_err) { error_propagate(errp, local_err); goto error; } /* Everything on disk uses Big Endian, so flip header fields * before writing them */ cpu_to_be16s(&luks->header.version); cpu_to_be32s(&luks->header.payload_offset); cpu_to_be32s(&luks->header.key_bytes); cpu_to_be32s(&luks->header.master_key_iterations); for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { cpu_to_be32s(&luks->header.key_slots[i].active); cpu_to_be32s(&luks->header.key_slots[i].iterations); cpu_to_be32s(&luks->header.key_slots[i].key_offset); cpu_to_be32s(&luks->header.key_slots[i].stripes); } /* Write out the partition header and key slot headers */ writefunc(block, 0, (const uint8_t *)&luks->header, sizeof(luks->header), &local_err, opaque); /* Delay checking local_err until we've byte-swapped */ /* Byte swap the header back to native, in case we need * to read it again later */ be16_to_cpus(&luks->header.version); be32_to_cpus(&luks->header.payload_offset); be32_to_cpus(&luks->header.key_bytes); be32_to_cpus(&luks->header.master_key_iterations); for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { be32_to_cpus(&luks->header.key_slots[i].active); be32_to_cpus(&luks->header.key_slots[i].iterations); be32_to_cpus(&luks->header.key_slots[i].key_offset); be32_to_cpus(&luks->header.key_slots[i].stripes); } if (local_err) { error_propagate(errp, local_err); goto error; } /* Write out the master key material, starting at the * sector immediately following the partition header. */ if (writefunc(block, luks->header.key_slots[0].key_offset * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, splitkey, splitkeylen, errp, opaque) != splitkeylen) { goto error; } memset(masterkey, 0, luks->header.key_bytes); g_free(masterkey); memset(slotkey, 0, luks->header.key_bytes); g_free(slotkey); g_free(splitkey); g_free(password); g_free(cipher_mode_spec); qcrypto_ivgen_free(ivgen); qcrypto_cipher_free(cipher); return 0; error: if (masterkey) { memset(masterkey, 0, luks->header.key_bytes); } g_free(masterkey); if (slotkey) { memset(slotkey, 0, luks->header.key_bytes); } g_free(slotkey); g_free(splitkey); g_free(password); g_free(cipher_mode_spec); qcrypto_ivgen_free(ivgen); qcrypto_cipher_free(cipher); g_free(luks); return -1; }
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id, const char *name, Error **errp) { BDRVQcowState *s = bs->opaque; QCowSnapshot sn; int snapshot_index, ret; /* Search the snapshot */ snapshot_index = find_snapshot_by_id_and_name(bs, snapshot_id, name); if (snapshot_index < 0) { error_setg(errp, "Can't find the snapshot"); return -ENOENT; } sn = s->snapshots[snapshot_index]; /* Remove it from the snapshot list */ memmove(s->snapshots + snapshot_index, s->snapshots + snapshot_index + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(sn)); s->nb_snapshots--; ret = qcow2_write_snapshots(bs); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to remove snapshot from snapshot list"); return ret; } /* * The snapshot is now unused, clean up. If we fail after this point, we * won't recover but just leak clusters. */ g_free(sn.id_str); g_free(sn.name); /* * Now decrease the refcounts of clusters referenced by the snapshot and * free the L1 table. */ ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset, sn.l1_size, -1); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to free the cluster and L1 table"); return ret; } qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t), QCOW2_DISCARD_SNAPSHOT); /* must update the copied flag on the current cluster offsets */ ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Failed to update snapshot status in disk"); return ret; } #ifdef DEBUG_ALLOC { BdrvCheckResult result = {0}; qcow2_check_refcounts(bs, &result, 0); } #endif return 0; }
static int cloop_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { BDRVCloopState *s = bs->opaque; uint32_t offsets_size, max_compressed_block_size = 1, i; int ret; bs->read_only = 1; /* read header */ ret = bdrv_pread(bs->file, 128, &s->block_size, 4); if (ret < 0) { return ret; } s->block_size = be32_to_cpu(s->block_size); if (s->block_size % 512) { error_setg(errp, "block_size %" PRIu32 " must be a multiple of 512", s->block_size); return -EINVAL; } if (s->block_size == 0) { error_setg(errp, "block_size cannot be zero"); return -EINVAL; } /* cloop's create_compressed_fs.c warns about block sizes beyond 256 KB but * we can accept more. Prevent ridiculous values like 4 GB - 1 since we * need a buffer this big. */ if (s->block_size > MAX_BLOCK_SIZE) { error_setg(errp, "block_size %" PRIu32 " must be %u MB or less", s->block_size, MAX_BLOCK_SIZE / (1024 * 1024)); return -EINVAL; } ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4); if (ret < 0) { return ret; } s->n_blocks = be32_to_cpu(s->n_blocks); /* read offsets */ if (s->n_blocks > (UINT32_MAX - 1) / sizeof(uint64_t)) { /* Prevent integer overflow */ error_setg(errp, "n_blocks %" PRIu32 " must be %zu or less", s->n_blocks, (UINT32_MAX - 1) / sizeof(uint64_t)); return -EINVAL; } offsets_size = (s->n_blocks + 1) * sizeof(uint64_t); if (offsets_size > 512 * 1024 * 1024) { /* Prevent ridiculous offsets_size which causes memory allocation to * fail or overflows bdrv_pread() size. In practice the 512 MB * offsets[] limit supports 16 TB images at 256 KB block size. */ error_setg(errp, "image requires too many offsets, " "try increasing block size"); return -EINVAL; } s->offsets = g_try_malloc(offsets_size); if (s->offsets == NULL) { error_setg(errp, "Could not allocate offsets table"); return -ENOMEM; } ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size); if (ret < 0) { goto fail; } for (i = 0; i < s->n_blocks + 1; i++) { uint64_t size; s->offsets[i] = be64_to_cpu(s->offsets[i]); if (i == 0) { continue; } if (s->offsets[i] < s->offsets[i - 1]) { error_setg(errp, "offsets not monotonically increasing at " "index %" PRIu32 ", image file is corrupt", i); ret = -EINVAL; goto fail; } size = s->offsets[i] - s->offsets[i - 1]; /* Compressed blocks should be smaller than the uncompressed block size * but maybe compression performed poorly so the compressed block is * actually bigger. Clamp down on unrealistic values to prevent * ridiculous s->compressed_block allocation. */ if (size > 2 * MAX_BLOCK_SIZE) { error_setg(errp, "invalid compressed block size at index %" PRIu32 ", image file is corrupt", i); ret = -EINVAL; goto fail; } if (size > max_compressed_block_size) { max_compressed_block_size = size; } } /* initialize zlib engine */ s->compressed_block = g_try_malloc(max_compressed_block_size + 1); if (s->compressed_block == NULL) { error_setg(errp, "Could not allocate compressed_block"); ret = -ENOMEM; goto fail; } s->uncompressed_block = g_try_malloc(s->block_size); if (s->uncompressed_block == NULL) { error_setg(errp, "Could not allocate uncompressed_block"); ret = -ENOMEM; goto fail; } if (inflateInit(&s->zstream) != Z_OK) { ret = -EINVAL; goto fail; } s->current_block = s->n_blocks; s->sectors_per_block = s->block_size/512; bs->total_sectors = s->n_blocks * s->sectors_per_block; qemu_co_mutex_init(&s->lock); return 0; fail: g_free(s->offsets); g_free(s->compressed_block); g_free(s->uncompressed_block); return ret; }
static void prop_get_fdt(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj); Error *err = NULL; int fdt_offset_next, fdt_offset, fdt_depth; void *fdt; if (!drc->fdt) { visit_start_struct(v, NULL, NULL, name, 0, &err); if (!err) { visit_end_struct(v, &err); } error_propagate(errp, err); return; } fdt = drc->fdt; fdt_offset = drc->fdt_start_offset; fdt_depth = 0; do { const char *name = NULL; const struct fdt_property *prop = NULL; int prop_len = 0, name_len = 0; uint32_t tag; tag = fdt_next_tag(fdt, fdt_offset, &fdt_offset_next); switch (tag) { case FDT_BEGIN_NODE: fdt_depth++; name = fdt_get_name(fdt, fdt_offset, &name_len); visit_start_struct(v, NULL, NULL, name, 0, &err); if (err) { error_propagate(errp, err); return; } break; case FDT_END_NODE: /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */ g_assert(fdt_depth > 0); visit_end_struct(v, &err); if (err) { error_propagate(errp, err); return; } fdt_depth--; break; case FDT_PROP: { int i; prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len); name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); visit_start_list(v, name, &err); if (err) { error_propagate(errp, err); return; } for (i = 0; i < prop_len; i++) { visit_type_uint8(v, (uint8_t *)&prop->data[i], NULL, &err); if (err) { error_propagate(errp, err); return; } } visit_end_list(v, &err); if (err) { error_propagate(errp, err); return; } break; } default: error_setg(&error_abort, "device FDT in unexpected state: %d", tag); } fdt_offset = fdt_offset_next; } while (fdt_depth != 0); }
static int qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds, Error **errp) { char *cacert = NULL, *cacrl = NULL, *cert = NULL, *key = NULL, *dhparams = NULL; int ret; int rv = -1; trace_qcrypto_tls_creds_x509_load(creds, creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>"); if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { if (qcrypto_tls_creds_get_path(&creds->parent_obj, QCRYPTO_TLS_CREDS_X509_CA_CERT, true, &cacert, errp) < 0 || qcrypto_tls_creds_get_path(&creds->parent_obj, QCRYPTO_TLS_CREDS_X509_CA_CRL, false, &cacrl, errp) < 0 || qcrypto_tls_creds_get_path(&creds->parent_obj, QCRYPTO_TLS_CREDS_X509_SERVER_CERT, true, &cert, errp) < 0 || qcrypto_tls_creds_get_path(&creds->parent_obj, QCRYPTO_TLS_CREDS_X509_SERVER_KEY, true, &key, errp) < 0 || qcrypto_tls_creds_get_path(&creds->parent_obj, QCRYPTO_TLS_CREDS_DH_PARAMS, false, &dhparams, errp) < 0) { goto cleanup; } } else { if (qcrypto_tls_creds_get_path(&creds->parent_obj, QCRYPTO_TLS_CREDS_X509_CA_CERT, true, &cacert, errp) < 0 || qcrypto_tls_creds_get_path(&creds->parent_obj, QCRYPTO_TLS_CREDS_X509_CLIENT_CERT, false, &cert, errp) < 0 || qcrypto_tls_creds_get_path(&creds->parent_obj, QCRYPTO_TLS_CREDS_X509_CLIENT_KEY, false, &key, errp) < 0) { goto cleanup; } } if (creds->sanityCheck && qcrypto_tls_creds_x509_sanity_check(creds, creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, cacert, cert, errp) < 0) { goto cleanup; } ret = gnutls_certificate_allocate_credentials(&creds->data); if (ret < 0) { error_setg(errp, "Cannot allocate credentials: '%s'", gnutls_strerror(ret)); goto cleanup; } ret = gnutls_certificate_set_x509_trust_file(creds->data, cacert, GNUTLS_X509_FMT_PEM); if (ret < 0) { error_setg(errp, "Cannot load CA certificate '%s': %s", cacert, gnutls_strerror(ret)); goto cleanup; } if (cert != NULL && key != NULL) { #if LIBGNUTLS_VERSION_NUMBER >= 0x030111 char *password = NULL; if (creds->passwordid) { password = qcrypto_secret_lookup_as_utf8(creds->passwordid, errp); if (!password) { goto cleanup; } } ret = gnutls_certificate_set_x509_key_file2(creds->data, cert, key, GNUTLS_X509_FMT_PEM, password, 0); g_free(password); #else /* LIBGNUTLS_VERSION_NUMBER < 0x030111 */ if (creds->passwordid) { error_setg(errp, "PKCS8 decryption requires GNUTLS >= 3.1.11"); goto cleanup; } ret = gnutls_certificate_set_x509_key_file(creds->data, cert, key, GNUTLS_X509_FMT_PEM); #endif if (ret < 0) { error_setg(errp, "Cannot load certificate '%s' & key '%s': %s", cert, key, gnutls_strerror(ret)); goto cleanup; } } if (cacrl != NULL) { ret = gnutls_certificate_set_x509_crl_file(creds->data, cacrl, GNUTLS_X509_FMT_PEM); if (ret < 0) { error_setg(errp, "Cannot load CRL '%s': %s", cacrl, gnutls_strerror(ret)); goto cleanup; } } if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams, &creds->parent_obj.dh_params, errp) < 0) { goto cleanup; } gnutls_certificate_set_dh_params(creds->data, creds->parent_obj.dh_params); } rv = 0; cleanup: g_free(cacert); g_free(cacrl); g_free(cert); g_free(key); g_free(dhparams); return rv; }