Introduction
Since upgrading my LG G2 phone to LG G4 and running Cyanogenmod 13 on it, I found that DroidSSHd application was not usable anymore.
This blog post is more or less a recollection of the steps to get it running, and to be able to ssh back to the phone.
Steps
1. .pid file access
DroidSSHd attempts to use the .pid file created by dropbear so that it can start / stop and keep track of the server running or not. The problem is that the .pid file created by the native server was not readable (due to SE Linux) by the UI application as it did not have the rights to read the file.
This was solved with these two commands that grant more rights to the .pid file – so inside DroidSSHdService.java:
cmd = String.format("chcon u:object_r:app_data_file:s0:c512,c768 %s", Base.getDropbearPidFilePath());
Also, if the daemon is ran as root, the .pid file will be created as root, thus UI won’t again be able to read it – so we need to make it owned by the user the UI runs with:
if (Base.runDaemonAsRoot()) { // uid is 0 if we run as root, but allow the UI access to the pid file. int uiUid = android.os.Process.myUid(); cmd = String.format("chown %s %s", uiUid, Base.getDropbearPidFilePath()); cmd(cmd); }
2. More .pid file troubles
While checking for the .pid file, DroidSSHd needs to have access to the /proc file system to check for self. However, under SE Linux of CM13 this is not possible anymore:
06-11 08:24:57.146: W/.bott.droidsshd(25168): type=1400 audit(0.0:39093): avc: denied { getattr } for path="/proc/30616" dev="proc" ino=6503439 scontext=u:r:untrusted_app:s0:c512,c768 tcontext=u:r:init:s0 tclass=dir permissive=0
Unfortunately, this one needs SuperSU (from chainfire) which would allow editing the security policy to grants access of untrusted_app to the /proc folder. Without SuperSU I found no way to get around this problem (the only other alternative I saw was to disable SE Linux completely).
Once SuperSU installed, the command below takes care of the access. For more information about supolicy, check chapter 5.5.1. The supolicy tool from chainfire’s How-to SU
supolicy --live "allow untrusted_app init dir { getattr }"
3. Linker is acting up
Attempting to connect to the ssh server failed (connection was closed right after authentication) but eventually I was able to get the error message (using the Close window on exit to Never in Putty):
CANNOT LINK EXECUTABLE: "/system/lib/libc++.so" is 32-bit instead of 64-bit page record for 0x7f800b8010 was not found (block_size=32)
This was extremely puzzling since the dropbearmulti was statically linked, so why would it want to access the phone’s libc++.so file ?!
Initially I thought that the armv6/32bit build of dropbearmulti caused the problem, thus why not trying an armv8-a/64bit build ? Same behavior though. Unfortunately this meant I had to get my hands dirty and use strace to dwelve into the linker problems.
[pid 25316] execve("/system/bin/sh", ["-sh"], [/* 17 vars */]) = 0 ... [pid 25316] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) = 0x7f9e3eb000 [pid 25316] prctl(0x53564d41 /* PR_??? */, 0, 0x7f9e3eb000, 0x1000, 0x7f9e3dc378) = 0 [pid 25316] openat(AT_FDCWD, "/system/lib/libc++.so", O_RDONLY|O_CLOEXEC) = 3 ...
Apparently, the problem happened when the code was trying to launch the shell /system/bin/sh and now it made sense. Pulling it locally and checking it, the shell IS a 64bit executable BUT somehow, it is dynamically linked!
$ file sh sh: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked (uses shared libs), BuildID[md5/uuid]=1047feab367159e3ef9fb609b6eb9fd0, stripped
Luckily I have an older bash 3.2 statically compiled (armv6/32bit) and I decided to give it a go. DroidSSHd has options to allow paths for SU and SH, but checking the code it seems they are only used after the connection is established (and not initially, upon session creation for the user). So a quick recompile with the /system/xbin/bash3 hardcoded, et voilà:
Remaining issues
- There are newer version of dropbear out there, including their patches for Android. I’ve downloaded the version dropbear-2016.73 and tried it, but it had problems. The patch was missing the atoi() instruction to convert the -U 0 argument to proper integer UID. I’ve decided not too loose time fixing even more problems, and went with the proven dropbear-0.52
- Most executables on my phone (such as ls, cp, etc … ) exhibit the same problem with CANNOT_LINK_EXECUTABLE when launched from dropbear, although they work properly from adb shell. I don’t have time to investigate why, I will probably go to a static build of busybox.
Geofferey
Did you ever figure out the root cause of the linker errors?
Geofferey Eakins
I figured it out!!!!! I hope this helps you too man. I spent the whole day looking for the solution.
Baiscally you need to modify a line in svr-chansession.c
From:
addnewvar(“LD_LIBRARY_PATH”, “/system/lib”);
To:
addnewvar(“LD_LIBRARY_PATH”, “/system/lib64”);
re-compile & viola, no more error when dropbear executes the shell and doesn’t attempt to link to a shared object in the wrong location. 🙂
Source of my epiphany:
http://k.japko.eu/android-dropbear.html