Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android MTP attach fails #6330

Open
Eric678 opened this issue Jan 5, 2021 · 29 comments
Open

Android MTP attach fails #6330

Eric678 opened this issue Jan 5, 2021 · 29 comments
Labels
affects-4.1 This issue affects Qubes OS 4.1. affects-4.2 This issue affects Qubes OS 4.2. C: usb proxy diagnosed Technical diagnosis has been performed (see issue comments). hardware support P: default Priority: default. Default priority for new issues, to be replaced given sufficient information. T: bug Type: bug report. A problem or defect resulting in unintended behavior in something that exists.

Comments

@Eric678
Copy link

Eric678 commented Jan 5, 2021

Qubes OS version:

R4.0 up to date current, Android 11 (Pixel phone up to date 5 dec 20 - reference platform)
f32 target Qube, f32-min sys-usb

Affected component(s) or functionality:

USB handling - dom0


Steps to reproduce the behavior:

Attach Android 11 device with file transfer enabled to a Qube running Nautilus.

Expected or desired behavior:

Entry for device appears in menu in Nautilus and I can select that item to browse the filesystem on the Android device.

Actual behavior:

Menu item appears as expected, however selection goes away for 5-10 sec then gives a popup "Unable to connect to MTP device 00n,00n" and deletes the Nautilus menu item.

General notes:

Please see forum thread for more details:
https://qubes-os.discourse.group/t/how-can-i-connect-to-android-via-usb/2101

An older v8 Android does partially work: same error popup in Nautilus, dismiss that, detach and reattach, then works as expected.

If looking into this I did notice another bug in the device widget communication - if Android file transfer is enabled or disabled while attached to a Qube the attachment is dropped in dom0, however the widget is not notified. Attempting detach in the widget gives a not attached error popup.


I have consulted the following relevant documentation:

I am aware of the following related, non-duplicate issues:

@andrewdavidwong andrewdavidwong added C: usb proxy needs diagnosis Requires technical diagnosis from developer. Replace with "diagnosed" or remove if otherwise closed. P: default Priority: default. Default priority for new issues, to be replaced given sufficient information. T: bug Type: bug report. A problem or defect resulting in unintended behavior in something that exists. labels Jan 6, 2021
@andrewdavidwong andrewdavidwong added this to the Release 4.0 updates milestone Jan 6, 2021
@0spinboson
Copy link

0spinboson commented Jan 6, 2021

This also happens here, in my Qubes 4.1 installation.

may or may not be related, but my guest-VM.logs in VMs after I've attacked any type of USB device are being spammed with "usb usb1: Not yet implemented", "vhci_hcd: urb'>status - 104" and "...unlink'->seqnum 7243041"
Attaching regular USB devices like microphones or webcams works fine, aside from the log spam.

@AlxHnr
Copy link

AlxHnr commented Jan 12, 2021

I have the same issue, but the phone can be mounted from inside sys-usb. (Or by re-attaching the USB PCI device to the VM which is running nautilus). The same applies to adb. See #5717

@0spinboson
Copy link

ah yes, it indeed works fine within sys-usb itself.

@marmarek : should I make a separate issue for the log spam issue?

@0spinboson
Copy link

0spinboson commented Jan 26, 2021

btw, the journal in sys-usb also has a stream of entries saying "unlinked by a call to usb_unlink_urb()', repeated every 5s.

@mfc
Copy link
Member

mfc commented Jun 5, 2021

i just want to confirm this issue, and that it is also present for target qube and sys-usb based on debian 10.

@DemiMarie
Copy link

More generally, it appears that kernel-mode USB drivers work, but user-mode USB drivers fail. Any idea why that is?

@iacore
Copy link

iacore commented Dec 21, 2021

Same issue here. lsusb show the device, but cannot mount the device with mtpfs, gvfs-mtp or aft-mtp-cli.

Most verbose log I found:

user@archlinux ~> aft-mtp-cli -v
creating device descriptor at /sys/bus/usb/devices/1-1
probing device 18d1:4ee1
capabilities = 0x000001ff
page size = 4096
<zero-packet> 
<bulk-continuation> 
<no-packet-size-limit> 
<bulk-scatter-gather> 
<reap-after-disconnect> 
<mmap> 
<drop-privileges> 
<conninfo-ex> 
<suspend> 
configurations: 1
interfaces: 1
Device usb interface: 0:0, index: 0, endpoints: 3
read control 80 06 0300 0000
languages[4]:
00000000: 04 03 09 04                                     ....

read control 80 06 03ee 0409
winusb handshake failed: ioctl: Broken pipe
descriptor[57]:
00000000: 12 01 00 02 00 00 00 40 d1 18 e1 4e 40 04 01 02 .......@...N@...
00000010: 03 01 09 02 27 00 01 01 04 c0 00 09 04 00 00 03 ....'...........
00000020: 06 01 01 05 07 05 81 02 00 02 00 07 05 01 02 00 ................
00000030: 02 00 07 05 82 03 1c 00 06                      .........

read control 80 06 0305 0409
interface name[8]:
00000000: 08 03 4d 00 54 00 50 00                         ..M.T.P.

10009 ms since the last poll call
Device::Find failed:timeout reaping usb urb

@gw0
Copy link

gw0 commented Dec 29, 2021

Same issue in Qubes 4.1 with USB PCI device in sys-net and Android 11. My hypothesis is the issue appears because the USB is controlled by the Android device (not the PC).

Steps to reproduce and some high-level logs:

## connect USB cable
## on Android set USB controlled by "This device" and use USB for "File transfer/Android Auto"

## dom0:
$ qvm-usb list
BACKEND:DEVID    DESCRIPTION
sys-net:2-1    Google_Pixel_3a_02CA...
$ qvm-usb attach --verbose personal sys-net:2-1

## sys-net:
$ sudo dmesg
[18566.214456] usb 2-1: new high-speed USB device number 36 using xhci_hcd
[18566.345080] usb 2-1: New USB device found, idVendor=18d1, idProduct=4ee1, bcdDevice= 4.40
[18566.345203] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[18566.345302] usb 2-1: Product: Pixel 3a
[18566.345354] usb 2-1: Manufacturer: Google
[18566.345549] usb 2-1: SerialNumber: 02CA...
[18812.887424] usbip-host 2-1: usbip-host: register new device (bus 2 dev 36)
[18812.891413] usbip-host 2-1: stub up

## personal:
$ sudo dmesg
[17256.651442] vhci_hcd vhci_hcd.0: pdev(0) rhport(0) sockfd(0)
[17256.651464] vhci_hcd vhci_hcd.0: devid(131108) speed(3) speed_str(high-speed)
[17256.651493] vhci_hcd vhci_hcd.0: Device attached
[17256.872744] usb 1-1: new high-speed USB device number 14 using vhci_hcd
[17256.990759] usb 1-1: SetAddress Request (14) to port 0
[17257.019751] usb 1-1: New USB device found, idVendor=18d1, idProduct=4ee1, bcdDevice= 4.40
[17257.019836] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[17257.019911] usb 1-1: Product: Pixel 3a
[17257.019949] usb 1-1: Manufacturer: Google
[17257.019986] usb 1-1: SerialNumber: 02CA...
$ jmtpfs ~/mnt
Device 0 (VID=18d1 and PID=4ee1) is a Google Inc Nexus/Pixel (MTP).
PTP_ERROR_IO: failed to open session, trying again after resetting USB interface
LIBMTP libusb: Attempt to reset device
LIBMTP PANIC: failed to open session on second attempt
terminate called after throwing an instance of 'MtpErrorCantOpenDevice'
  what():  Can't open device
Aborted
$ sudo dmesg
[17449.548755] usb 1-1: reset high-speed USB device number 14 using vhci_hcd
[17449.668768] usb 1-1: SetAddress Request (14) to port 0
[17449.812594] usb 1-1: reset high-speed USB device number 14 using vhci_hcd
[17449.931749] usb 1-1: SetAddress Request (14) to port 0
[17509.958094] vhci_hcd: unlink->seqnum 257
[17509.958148] vhci_hcd: urb->status -104

## sys-net:
$ sudo dmesg
[19005.674190] usbip-host 2-1: unlinked by a call to usb_unlink_urb()
[19066.197678] usbip-host 2-1: unlinked by a call to usb_unlink_urb()
[19125.811047] usbip-host 2-1: unlinked by a call to usb_unlink_urb()

## personal:
$ go-mtpfs ~/mnt
2021/12/29 12:33:21 OpenSession failed: LIBUSB_ERROR_TIMEOUT; attempting reset
2021/12/29 12:33:28 Configure failed: OpenSession after reset: LIBUSB_ERROR_TIMEOUT
$ mtp-detect 
libmtp version: 1.1.16

Listing raw device(s)
Device 0 (VID=18d1 and PID=4ee1) is a Google Inc Nexus/Pixel (MTP).
   Found 1 device(s):
   Google Inc: Nexus/Pixel (MTP) (18d1:4ee1) @ bus 1, dev 14
Attempting to connect device(s)
PTP_ERROR_IO: failed to open session, trying again after resetting USB interface
LIBMTP libusb: Attempt to reset device
LIBMTP PANIC: failed to open session on second attempt
Unable to open raw device 0
OK.

@iacore
Copy link

iacore commented Dec 31, 2021

My hypothesis is the issue appears because the USB is controlled by the Android device (not the PC).

USB tethering works (if connecting Android device to sys-net) and that is controlled by Android.

@gw0
Copy link

gw0 commented Jan 3, 2022

My hypothesis is the issue appears because the USB is controlled by the Android device (not the PC).

USB tethering works (if connecting Android device to sys-net) and that is controlled by Android.

Sure, everything works in sys-net, because the USB PCI device is attached to this VM (as @AlxHnr said). For example MTP attach in sys-net when controlled by Android:

## sys-net:
$ sudo apt-get install jmtpfs
$ jmtpfs mnt
Device 0 (VID=18d1 and PID=4ee1) is a Google Inc Nexus/Pixel (MTP).
Android device detected, assigning default bug flags
$ ls -al mnt
total 4
drwxr-xr-x  3 user user    0 Jan  1  1970  .
drwxrwxrwt 14 root root 4096 Jan  3 09:50  ..
drwxr-xr-x 22 user user    0 Nov 25  8502 'Internal shared storage'
$ fusermount -u mnt

But the forwarding/reattaching just the Android USB device (not PCI) to another VM does not work. Because this works perfectly for slave USB devices, my hypothesis is that the issue is because USB is controlled by the Android device.

@iacore
Copy link

iacore commented Jan 3, 2022

I meant sys-net, not sys-usb.

In USB tethering mode, it's still controlled by the Android device. Yet it works (connecting the android device form sys-usb to sys-net.

@AlxHnr
Copy link

AlxHnr commented Mar 10, 2022

Still occurs on the latest Qubes 4.1 with fedora 34 as App VM.

@Szewcson
Copy link

Szewcson commented Sep 2, 2022

In android 12 there is option to change the device that controlling usb. Unfortunately it causes detachment from VM, and ends with error on android side. I tried with attaching android device persistently but it not works. It also not work on Windows VM as I mentioned in #7731

@SurienDG
Copy link

SurienDG commented Sep 3, 2022

Yea I think the main problem is the detachment when changing "Use USB for" options on your Android device. In Android 8 in order for it to work for me I had to set my device to default to always connect with mtp mode rather than the charging mode (since it couldn't be changed once connected to a VM). Now in Android 13 when I first connect it in sys-usb with the "No data transfer" option and I click to mount it works but gives me an empty folder with no files (since I selected no transfer). However, once I disconnect it and try to reconnect it (still in sys-usb) I get the "Unable to connect to MTP device 00n,00n" error.

Now if I change the mode on my Android device to "File transfer" and try to mount it again then it works successfully in sys-usb. Now if I unmount it after doing this and try to reconnect still in sys-usb still with the "File transfer" option I again get the MTP error.

Thus, this makes me think that the issue is that on Android 11+ right after you set your option for "Use USB for" you can mount but cannot remount without changing your setting which could explain why it cannot be assigned from sys-usb to another qube because that would result in another mount after the first successful one in sys-usb.

Does that make sense? If is there a way we can prevent consecutive mounts as that seems to be causing the problem on newer Android versions based on my testing and what I've read in this issue thread. What do you all think?

@Szewcson
Copy link

Szewcson commented Sep 3, 2022

I was finally able to connect using windows VM and images transfer mode on android. But it works only sometimes and I was not able to figure out during which conditions. File transfer mode never work for me, and usb modem mode seems to work almost always.

@andrewdavidwong andrewdavidwong added the affects-4.1 This issue affects Qubes OS 4.1. label Aug 8, 2023
@andrewdavidwong andrewdavidwong removed this from the Release 4.1 updates milestone Aug 13, 2023
@UndeadDevel
Copy link

Affects 4.2.

FWIW, in sys-usb the Android phone does automount and can immediately be opened and browsed in Thunar, but attaching it to any other qube that I've tried doesn't seem to work...no errors in dom0 dmesg or journalctl but nothing new pops up in /dev/ or lsblk in the target qube.

@DemiMarie
Copy link

Nothing in lsblk is expected. MTP does not expose a block device and is implemented in userspace.

@UndeadDevel
Copy link

Nothing in lsblk is expected. MTP does not expose a block device and is implemented in userspace.

Ah. Well, forgive my ignorance; it does show up in the Devices widget under "USB Devices", however, so I thought it should at least pop up as a device in /dev/, but nothing new appears there.

I've tried jmtpfs mymountpoint but that fails with

Device 0 (VID=0e8d and PID=2008) is a MediaTek Inc MT65xx.
PTP_ERROR_IO: failed to open session, trying again after resetting USB interface
LIBMTP libusb: Attempt to reset device
LIBMTP PANIC: failed to open session on second attempt
terminate called after throwing an instance of 'MtpErrorCantOpenDevice'
  what():  Can't open device
Aborted

@DemiMarie
Copy link

@UndeadDevel did you remember to attach the USB device?

@UndeadDevel
Copy link

Of course...using the Devices widget.

If I turn File Transfer off on the phone after attaching and then detach (again using the widget) then it gives an error saying that nothing was attached, so I presume it detaches itself in that case; if I leave File Transfer enabled, however, there is no error, so I assume that it is attached and detached as expected when I trigger these events using the widget.

@marmarek
Copy link
Member

marmarek commented Jan 5, 2024

AFAIR Android resets the USB device side when switching mode to MTP (or any other). This detaches the device from the target qube, but it seems to be possible to select file transfer mode before attaching the device, and the selected mode seems to survive attaching to a qube. And also, while I get exactly the same error, the "libusb: Attempt to reset device" seems to not detach device from the target qube anymore, which is a progress I'd say.

At this point, I can confirm it doesn't work, but also I don't see any obvious reason why. The reset detaching the device (or attach resetting the MTP mode) used to be a problem, but it isn't the case anymore. "USB tethering" mode seems to work just fine, so it isn't generic Android USB issue, it is something specific to MTP.

@DemiMarie
Copy link

This detaches the device from the target qube

I’m pretty sure this is the bug. User-mode applications expect that the device will remain attached in this case and break otherwise. There may be a timeout, but it is too short for anything that requires user confirmation. For Android to work, reattachment will need to happen automatically and without a prompt.

Is it possible to distinguish resetting of the USB device from the USB device being physically disconnected?

@marmarek
Copy link
Member

Is it possible to distinguish resetting of the USB device from the USB device being physically disconnected?

In general case - no. Some devices even really disconnect data lines on reset; and AFAIR the XHCI interface doesn't give you much more than "disconnect" + "connect" events in that case. But maybe in some cases there is some trick to detect such case.

But also, see my comment above: disconnect on mode switch is no longer the thing that breaks MTP, so this aspect is offtopic for this issue.

@DemiMarie
Copy link

I’m guessing that some system call is failing for some reason.

@ryrona2
Copy link

ryrona2 commented Apr 14, 2024

This this issue affects me as well, I decided to do some investigations. I used Wireshark in sys-usb to monitor the /dev/usbmonX device node my Android device is connected to. My Android device runs latest Graphene OS.

I have found the problem. If more than one SET_CONFIGURATION control packet is ever sent to the Android device, it will refuse to answer to any data packet sent to it forever, and only answer to control packets.

This can happen in the following cases:

Case 1: One SET_CONFIGURATION is sent to enable the device when it is attached to the qube running the USB driver, typically sys-usb. When the USB device is assigned in into another qube, two more SET_CONFIGURATION is sent, one to disable and one to re-enable the device, the latter originating from the newly assigned qube rather than the one running the USB driver. The MTP device cannot be mounted from within any qube, all data packets from host to device will timeout without getting any response.

Case 2: One SET_CONFIGURATION is sent to enable the device when it is attached to the qube running the USB driver. Now, the MTP device can be mounted and browsed just fine from within that qube. But when unmounting the MTP device, a PORT_RESET/C_PORT_RESET is sent to the device and then after that of course a new SET_CONFIGURATION is sent to enable the device after the reset. Now it won't work to mount the MTP device again, not even from the qube running the USB driver. All packets from host to device will timeout without getting any response.

Case 3: One SET_CONFIGURATION is sent to enable the device when it is attached to the qube running the USB driver. You can manually send another to "enable" the device again despite it already being enabled by "echo 1 > bConfigurationValue" for the /sys node of the USB device. Now mounting the MTP device even from within the USB driver qube won't work. All packets from host to device will timeout without getting any response.

This only affects Android devices. The Android device can easily be reset to work again by either unplugging and replugging the cable, or by switching USB mode to "No data transfer" and then back to "MTP" in the UI of the Android device. Resetting the device from host does not work however, it must be reset physically or from the Android device.

All parts of Android USB interfacing components seem to have the same or similar issues, including fastboot (the bootloader interface). USB debugging (adb) is a bit different, because it actually resets the device if it gets a second SET_CONFIGURATION, and then recovers cleanly. But this still prevents assigning it into another qube, since resetting the device means it momentarily disappears as if unplugged.

This issue can also be reproduced on Ubuntu using case 2 and 3, so the issue is not Qubes OS specific.

All other devices than Android devices seem to handle multiple SET_CONFIGURATION just fine, including disabling an re-enabling. But Android seem to have issues in most or all of its USB facing components.

My current suspicion is a driver bug in Android (and Pixel bootloader for fastboot), or possibly that some hardening feature against USB tampering on Android (and Pixel bootloader) is triggering on this, distrusting host until user resets the connection manually. I do not believe Qubes OS nor Ubuntu is at fault here.

Logical next step in debugging this would be to try figuring out exactly why Android decides to no longer respond, but this involves debugging on the Android device. A bug report against Android should probably also be opened. I am uncertain if Qubes OS should attempt any workaround, or what such a workaround could be.

@DemiMarie
Copy link

Nice catch @ryrona2!

@DemiMarie
Copy link

The obvious workaround is for sys-usb to not send SET_CONFIGURATION at all. @ryrona2: can you test the following setup?

  • Add usbcore.authorized_default=0 to sys-usb kernel command line.
  • Install USBGuard in sys-usb. Configure it to not authorize the Android device.
  • Enable current-testing repository in sys-usb’s template and upgrade app-linux-usb-proxy to the latest version.

If you run into #9104, the patch in QubesOS/qubes-app-linux-usb-proxy#35 will make attach succeed again.

My hope is that with this setup, sys-usb never sends SET_CONFIGURATION at all.

@andrewdavidwong andrewdavidwong added diagnosed Technical diagnosis has been performed (see issue comments). and removed needs diagnosis Requires technical diagnosis from developer. Replace with "diagnosed" or remove if otherwise closed. labels Apr 14, 2024
@ryrona2
Copy link

ryrona2 commented Apr 16, 2024

I did test this quickly. Now sys-usb wouldn't send any SET_CONFIGURATION anymore, but the qube I assign the device into sends multiple, including one to disable the device and one to re-enable it. I don't really understand why it does this, it should have behaved like sys-usb usually does, just enabling the device once. But MTP still didn't work inside the qube probably because of the multiple SET_CONFIGURATION calls.

I am wondering, maybe the best solution really would be an MTP proxy, similar to how block devices are proxied. This way sys-usb would still handle the SET_CONFIGURATION, but only sys-usb, because the actual USB device is not assigned into any qube, just the MTP proxy. Because, I mean, even if we did prevent sys-usb from setting up the device like you suggest, if we re-assign the USB device between qubes, each qube would still send a new SET_CONFIGURATION, so it would still be pretty broken for devices that does not support multiple SET_CONFIGURATION calls.

I had a quick chat with someone on GrapheneOS developer chat, and they didn't seem to excited about changing the behavior, saying Linux and QubesOS is doing wrong if they ever send more than one SET_CONFIGURATION call, because they say neither Windows, MacOS or even Android ever does that. I don't really know what the USB standard says.

@DemiMarie
Copy link

I did test this quickly. Now sys-usb wouldn't send any SET_CONFIGURATION anymore, but the qube I assign the device into sends multiple, including one to disable the device and one to re-enable it. I don't really understand why it does this, it should have behaved like sys-usb usually does, just enabling the device once. But MTP still didn't work inside the qube probably because of the multiple SET_CONFIGURATION calls.

Is there a SET_CONFIGURATION after the device is attached to the VM, but before MTP tries to use the device? I think this is a USBIP bug.

I am wondering, maybe the best solution really would be an MTP proxy, similar to how block devices are proxied. This way sys-usb would still handle the SET_CONFIGURATION, but only sys-usb, because the actual USB device is not assigned into any qube, just the MTP proxy. Because, I mean, even if we did prevent sys-usb from setting up the device like you suggest, if we re-assign the USB device between qubes, each qube would still send a new SET_CONFIGURATION, so it would still be pretty broken for devices that does not support multiple SET_CONFIGURATION calls.

I had a quick chat with someone on GrapheneOS developer chat, and they didn't seem to excited about changing the behavior, saying Linux and QubesOS is doing wrong if they ever send more than one SET_CONFIGURATION call, because they say neither Windows, MacOS or even Android ever does that. I don't really know what the USB standard says.

This seems like a Linux kernel bug to me. Could you report this on linux-usb@vger.kernel.org?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
affects-4.1 This issue affects Qubes OS 4.1. affects-4.2 This issue affects Qubes OS 4.2. C: usb proxy diagnosed Technical diagnosis has been performed (see issue comments). hardware support P: default Priority: default. Default priority for new issues, to be replaced given sufficient information. T: bug Type: bug report. A problem or defect resulting in unintended behavior in something that exists.
Projects
Status: Devices: misc
Development

No branches or pull requests