usb: mtp fixes, guest-reset switch for usb-host.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJcgOozAAoJEEy22O7T6HE4EzEP/3oPKSSMhxdk8gy///7aoF8V
 grBlDQPca+RBUnJyqPg7iBFO0uO+uxNVd5JYUnNuMYfTBgzJXNtLmWIZY0uHHT/u
 8oYju5ayYK+n4nwcmDDYO5gfNq6zIVqfn/Ur6GurdDlrJQQ0ERU7e4M2WUpB2lgo
 2Gar52fSovjV37ql5gBYeLlxADKNOxQqGeUS7k6fkxktu/hPrnmjBzzdLbntHP7B
 lzytUcEPej76Pm1SVQZgUewSnjpjVUAFNmWH79NpSk23VD8Q2ANE2SJFF43lxA/S
 vm7iklbpjrJVHOCNSQGmGKfXnO+39UMfzVmJwOmX1DMuO8zb4K6bSxUX578P6BPa
 Jm3qA3zE26ZkB2PlcA/XNkw2YoCBX6v+U8M7sjfRqfFLDLgvI54ZreGovM4Ai/65
 H0KENMRvn+5Kb4p5wQ/z57aSbdXrXFCJIiKoPr6JrOOMpq7t3sSUY6Am418NilJE
 9g+ahZrdF4NlQIQE4EnLw9vuMUvYspsYvs6qHkUe0dDPLh0elcplCVQgprsTncA1
 YFLCwZMR7c1W/OzETSFcx9ph9n0UejXwGXDKR7/DoLXJsX/gqaPDExfBbMO6wYBN
 oXXV5/jiLPrsKREP1xm2nIREZrxmwlpg55jmtaYJ1FSa1I7hzFl7e9/bccGFWPah
 BN4CB8cPdGNkyDNktMfK
 =UGuj
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/usb-20190307-pull-request' into staging

usb: mtp fixes, guest-reset switch for usb-host.

# gpg: Signature made Thu 07 Mar 2019 09:53:55 GMT
# gpg:                using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/usb-20190307-pull-request:
  Introduce new "no_guest_reset" parameter for usb-host device
  usb-mtp: prevent null dereference while deleting objects
  usb-mtp: fix some usb_mtp_write_data return paths
  usb-mtp: return incomplete transfer on a lstat failure

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-03-07 14:06:42 +00:00
commit 3a75ef6a0f
2 changed files with 31 additions and 17 deletions

View file

@ -1177,9 +1177,7 @@ static int usb_mtp_deletefn(MTPState *s, MTPObject *o, uint32_t trans)
usb_mtp_object_free_one(s, o);
success = true;
}
}
if (o->format == FMT_ASSOCIATION) {
} else if (o->format == FMT_ASSOCIATION) {
if (rmdir(o->path)) {
partial_delete = true;
} else {
@ -1591,17 +1589,21 @@ done:
return ret;
}
static void usb_mtp_update_object(MTPObject *parent, char *name)
static int usb_mtp_update_object(MTPObject *parent, char *name)
{
int ret = -1;
MTPObject *o =
usb_mtp_object_lookup_name(parent, name, strlen(name));
if (o) {
lstat(o->path, &o->stat);
ret = lstat(o->path, &o->stat);
}
return ret;
}
static void usb_mtp_write_data(MTPState *s)
static int usb_mtp_write_data(MTPState *s)
{
MTPData *d = s->data_out;
MTPObject *parent =
@ -1609,6 +1611,7 @@ static void usb_mtp_write_data(MTPState *s)
char *path = NULL;
uint64_t rc;
mode_t mask = 0644;
int ret = 0;
assert(d != NULL);
@ -1617,13 +1620,13 @@ static void usb_mtp_write_data(MTPState *s)
if (!parent || !s->write_pending) {
usb_mtp_queue_result(s, RES_INVALID_OBJECTINFO, d->trans,
0, 0, 0, 0);
return;
return 1;
}
if (s->dataset.filename) {
path = g_strdup_printf("%s/%s", parent->path, s->dataset.filename);
if (s->dataset.format == FMT_ASSOCIATION) {
d->fd = mkdir(path, mask);
ret = mkdir(path, mask);
goto free;
}
d->fd = open(path, O_CREAT | O_WRONLY |
@ -1653,15 +1656,21 @@ static void usb_mtp_write_data(MTPState *s)
goto done;
}
if (d->write_status != WRITE_END) {
return;
g_free(path);
return ret;
} else {
/* Only for < 4G file sizes */
if (s->dataset.size != 0xFFFFFFFF && d->offset != s->dataset.size) {
/*
* Return an incomplete transfer if file size doesn't match
* for < 4G file or if lstat fails which will result in an incorrect
* file size
*/
if ((s->dataset.size != 0xFFFFFFFF &&
d->offset != s->dataset.size) ||
usb_mtp_update_object(parent, s->dataset.filename)) {
usb_mtp_queue_result(s, RES_INCOMPLETE_TRANSFER, d->trans,
0, 0, 0, 0);
goto done;
}
usb_mtp_update_object(parent, s->dataset.filename);
}
}
@ -1676,12 +1685,14 @@ done:
*/
if (d->fd != -1) {
close(d->fd);
d->fd = -1;
}
free:
g_free(s->dataset.filename);
s->dataset.size = 0;
g_free(path);
s->write_pending = false;
return ret;
}
static void usb_mtp_write_metadata(MTPState *s, uint64_t dlen)
@ -1718,14 +1729,12 @@ static void usb_mtp_write_metadata(MTPState *s, uint64_t dlen)
s->write_pending = true;
if (s->dataset.format == FMT_ASSOCIATION) {
usb_mtp_write_data(s);
/* next_handle will be allocated to the newly created dir */
if (d->fd == -1) {
if (usb_mtp_write_data(s)) {
/* next_handle will be allocated to the newly created dir */
usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
0, 0, 0, 0);
return;
}
d->fd = -1;
}
usb_mtp_queue_result(s, RES_OK, d->trans, 3, QEMU_STORAGE_ID,

View file

@ -82,7 +82,7 @@ struct USBHostDevice {
uint32_t options;
uint32_t loglevel;
bool needs_autoscan;
bool allow_guest_reset;
/* state */
QTAILQ_ENTRY(USBHostDevice) next;
int seen, errcount;
@ -1456,6 +1456,10 @@ static void usb_host_handle_reset(USBDevice *udev)
USBHostDevice *s = USB_HOST_DEVICE(udev);
int rc;
if (!s->allow_guest_reset) {
return;
}
trace_usb_host_reset(s->bus_num, s->addr);
rc = libusb_reset_device(s->dh);
@ -1573,6 +1577,7 @@ static Property usb_host_dev_properties[] = {
DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0),
DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames, 32),
DEFINE_PROP_BOOL("guest-reset", USBHostDevice, allow_guest_reset, true),
DEFINE_PROP_UINT32("loglevel", USBHostDevice, loglevel,
LIBUSB_LOG_LEVEL_WARNING),
DEFINE_PROP_BIT("pipeline", USBHostDevice, options,