1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-14 03:30:02 +00:00

trezorlib: workaround for a problem with Trezor One webusb

when webusb version of T1 is wiped, the usb device changes serial
immediately (unlike TT, which changes it after reconnect).

That confuses libusb on linux, and next time the device is reset, it
will insist on re-enumeration.

To solve this, we leave some explanatory comments, and trigger the
device reset through opening the device right after a wipe.
The client instance is unusable after that, but not much we can do about
it, and on next run trezorctl will behave as if nothing bad happened.
This commit is contained in:
matejcik 2019-02-26 17:31:44 +01:00
parent 18eab21932
commit 0a8b5a08c2
3 changed files with 31 additions and 6 deletions

View File

@ -374,7 +374,8 @@ def wipe_device(connect, bootloader):
click.echo("Wiping user data!")
try:
return device.wipe(connect())
device.wipe(client)
click.echo("Device wiped")
except tools.CallException as e:
click.echo("Action failed: {} {}".format(*e.args))
sys.exit(3)

View File

@ -45,6 +45,7 @@ class TrezorDevice:
@expect(proto.Success, field="message")
@session
def apply_settings(
client,
label=None,
@ -74,6 +75,7 @@ def apply_settings(
@expect(proto.Success, field="message")
@session
def apply_flags(client, flags):
out = client.call(proto.ApplyFlags(flags=flags))
client.init_device() # Reload Features
@ -81,6 +83,7 @@ def apply_flags(client, flags):
@expect(proto.Success, field="message")
@session
def change_pin(client, remove=False):
ret = client.call(proto.ChangePin(remove=remove))
client.init_device() # Re-read features
@ -93,14 +96,26 @@ def set_u2f_counter(client, u2f_counter):
return ret
@expect(proto.Success, field="message")
def wipe(client):
ret = client.call(proto.WipeDevice())
client.init_device()
return ret
def wipe(client) -> bool:
"""Initiate device wipe.
Returns whether it's safe to continue using the client instance.
(see comment in `WebUsbHandle.open`)
"""
# This is not marked @session by design: the subsequent init_device should run
# in a separate session, so that when it triggers a USB error, a subsequent
# re-enumeration fixes it. See comment in WebUsbHandle.open
# XXX this should actually call the USB reset explicitly
client.call(proto.WipeDevice())
try:
client.init_device()
return True
except Exception:
return False
@expect(proto.Success, field="message")
@session
def recover(
client,
word_count=24,

View File

@ -53,7 +53,16 @@ class WebUsbHandle:
else:
args = ()
raise IOError("Cannot open device", *args)
self.handle.resetDevice()
# XXX this may fail with LIBUSB_ERROR_NOT_FOUND
# This will usually happen after device wipe, because USB serial has changed,
# and requires re-enumeration and reacquiring of the device.
# I haven't found a reasonable way of handling it here, or in the enumeration
# step. (In particular, it seems impossible to force libusb to re-enumerate
# explicitly, without calling device reset.)
# So now I'm just leaving it here to crash in some cases.
self.handle.claimInterface(self.interface)
def close(self) -> None: