Protect what matters – even after you're gone. Make a plan for your digital legacy today.
Forum Discussion
edtpg
2 years agoNew Contributor
Linux desktop client crashes on startup
Since updating to the latest version of the client, the Linux desktop client consistently crashes on first startup, and sometimes crashes again after already running.
I have the browser extension ...
- 10 months ago
Hello folks,
I'm sorry that 1Password for Linux is crashing when you first first boot your device. This is a known issue that our development team is investigating and hopes to fix in a future update to 1Password. While I don't have a timeline on when a fix will be released, the fix will be noted in our release notes as soon as it is available.
As noted in this thread, the issue should only affect the first launch after boot and subsequent launches of the 1Password app should work normally. If you're seeing different behaviour then please reach out to support@1Password.com so that we can dig deeper.
-Dave
pwhz
2 months agoNew Contributor
I've been experimenting with this and after a bit of reverse engineering I managed to hack together a fix. The fix is simple in principle but it's quite a technical process. I thought I'd share it for those who want to try it. I'll describe the process for x86 because that's all I've tried, but you could probably do something similar on ARM.
As Dave figured out here, it seems like 1Password is not actually crashing (but it might as well be). The error message refers to an improper exit when 1Password was last running. There's a bug which means that 1Password takes ages to start up properly after the error message is dismissed, and an error message followed by nothing happening looks like a crash. The reason this happens on boot is, I think, because 1Password doesn't properly exit when the system is shutting down (unless it is manually closed first). When 1Password is launched after the system has booted, it checks for evidence of an unclean exit when it was last running. It will find this evidence because it didn't exit correctly on the previous shutdown. When it finds the evidence, it shows the popup and triggers the startup delay bug.
The "fix" is to patch 1Password so that it never sees any crash reports from the unclean exit. The function to patch is op_crash_reporting::crash_report::CrashReport::check_for_crash_reports, and it is in the binary /path/to/1Password installation/resources/app.asar.unpacked/index.node. On my Manjaro system this is /opt/1Password/resources/app.asar.unpacked/index.node.
Before it actually looks for any crash reports, check_for_crash_reports checks if op_crash_reporting::killswitch::CRASH_REPORTING_KILL_SWITCH is enabled. If it is, then it just returns zero, as though there are no crash reports. This is compiled as a conditional jump: "if the kill switch is enabled, then jump to the bit that returns zero". We patch the jump instruction so that it always jumps to the bit that returns zero, regardless of whether the kill switch is set. The caller of the function is led to believe that there are no crash reports, so 1Password starts normally, without a popup or delay.
The code moves around between 1Password versions (I've tried 8.11.12 and 8.11.14), so to find the exact location of the instruction to patch we use objdump to find the function by name and disassemble it:
objdump -FC -Mintel --disassemble="op_crash_reporting::crash_report::CrashReport::check_for_crash_reports" /opt/1Password/resources/app.asar.unpacked/index.nodeHere's my annotated version of the relevant part of the output of that command (on 8.11.14):
| 000000000468d280 <op_crash_reporting::crash_report::CrashReport::check_for_crash_reports> (File Offset: 0x468c280):
| 468d280: 55 push rbp
| 468d281: 41 57 push r15
| 468d283: 41 56 push r14
| 468d285: 41 55 push r13
| 468d287: 41 54 push r12
| 468d289: 53 push rbx
| 468d28a: 48 81 ec 08 01 00 00 sub rsp,0x108
| 468d291: 48 89 f3 mov rbx,rsi
| 468d294: 49 89 fe mov r14,rdi
| 468d297: 48 8b 05 c2 2c 07 03 mov rax,QWORD PTR [rip+0x3072cc2] # 76fff60 <op_crash_reporting::killswitch::CRASH_REPORTING_KILL_SWITCH> (File Offset: 0x76fef60)
| 468d29e: 48 83 f8 02 cmp rax,0x2
| 468d2a2: 0f 85 3b 02 00 00 jne 468d4e3 <op_crash_reporting::crash_report::CrashReport::check_for_crash_reports+0x263> (File Offset: 0x468c4e3)
(load kill switch) --> | 468d2a8: 0f b6 05 b9 2c 07 03 movzx eax,BYTE PTR [rip+0x3072cb9] # 76fff68 <op_crash_reporting::killswitch::CRASH_REPORTING_KILL_SWITCH+0x8> (File Offset: 0x76fef68)
(check kill switch) --> | 468d2af: a8 01 test al,0x1
THIS JUMP --> | 468d2b1: 0f 84 95 01 00 00 je 468d44c <op_crash_reporting::crash_report::CrashReport::check_for_crash_reports+0x1cc> (File Offset: 0x468c44c)
| 468d2b7: 48 8d 7c 24 20 lea rdi,[rsp+0x20]
| 468d2bc: 4c 89 f6 mov rsi,r14
| 468d2bf: 48 89 da mov rdx,rbx
| 468d2c2: e8 19 05 00 00 call 468d7e0 <op_crash_reporting::crash_report::crash_files> (File Offset: 0x468c7e0)(The disassembly for 8.11.12 looks much the same, except that the memory addresses are different. Until this function is modified significantly in an update, it should be possible to identify the instructions above in future versions of 1Password.)
The instruction to patch is the je marked "THIS JUMP". We can read its memory address from the column on the left (here, it's 0x468d2b1). We need the file offset so we can edit the instruction. The difference between the memory addresses and file offsets is the difference between the two hexadecimal numbers on the first line of the disassembly: in this case, it's 0x468d280 - 0x468c280 = 0x1000. So the offset of the target instruction in the file is 0x468d2b1 - 0x1000 = 0x468c2b1 for this version. (The file offset of the target instruction is not always the same. It's different (0x2d7d9e1) in 8.11.12, for example.)
Open index.node in a hex editor and go to the file offset just calculated (0x468c2b1 for me). You should see the bytes 0f 84 xx xx xx xx (0f 84 95 01 00 00 in this case). Change the first two bytes to 48 e9. This changes the je instruction to jmp, which is an unconditional jump.
To save the file you will likely need root access, so it might be easiest to save elsewhere and sudo mv it into the correct location. I recommend keeping the old file as a backup. For instance, my unpatched binary is at /opt/1Password/resources/app.asar.unpacked/index.node.unpatched. The patched binary goes where the original was, so 1Password will use it instead. If you mess up the patch and 1Password stops working, you can just go back to the original binary without needing to reinstall anything.
You'll have to reapply the patch every time 1Password is updated. I did when I went from 8.11.12 to 8.11.14.
- pwhz2 months agoNew Contributor
This patch doesn't work anymore on 8.11.16 because check_for_crash_reports no longer checks the kill switch (all of a sudden...?).
You can achieve the same effect as the above by patching op_crash_reporting::crash_report::crash_files like this: Find the first call to <FilterMap as Iterator>::next (it's not long after the call to Iterator::collect). Immediately after, there are cmp and je instructions. The je is encoded as 75 10. Change these bytes to 90 90 to swap the jump for two NOPs. (This edit was at 0x4743F85 in the file for me on 8.11.16-35.)
This works because the cmp and je are checking if next() returned None, and the next() is on an iterator of crash report files. NOPing the je makes execution fall through to the None case, so the loop that processes the crash report files never runs, and so crash_files returns nothing.
I'm going to keep using these patches because they completely fix the issue for me, both on boot and when 1P is terminated and restarted while the system remains running, but I'll avoid posting too much about it here because 1Password's own community forum isn't really the right place ;)
I found a blog post which has a nice idea for fixing the boot issue by creating a systemd service to delete the crash reports on boot so that 1Password doesn't see them. This is probably more useful for most people: https://oltdaniel.eu/notes/fix-1password-crash-report-popup/