Cross Compiling Dropbear for Android(API 23) with Auto Run on Boot


Compiling a random Linux compatible cli tool for Android can be painful. The Android, although with a Linux kernel, has a very different experience. It has bionic as its C library and linker, the SELinux can be troublesome, lacks common library support out of box (e.g. openssl), no common cli tools, different init system and file system hierarchy. I found precompiled binaries not suitable for my situation (and really we should not trust binaries from internet), so I decided to compile on my own.

Compiling

Download and set up Android NDK. Clone the dropbear source code.

export PATH="/opt/android-ndk-r27/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH"
git clone -b DROPBEAR_2024.85 -d 1 https://github.com/mkj/dropbear/tree/DROPBEAR_2024.85

Before building the program, let’s do some quick hacks:

src/default_options.h:

// change the default port
#define DROPBEAR_DEFPORT "2022"

// where /etc lays may be mounted as ro
// change the following file path
#define DSS_PRIV_FILENAME "/data/dropbear/dropbear_dss_host_key"
#define RSA_PRIV_FILENAME "/data/dropbear/dropbear_rsa_host_key"
#define ECDSA_PRIV_FILENAME "/data/dropbear/dropbear_ecdsa_host_key"
#define ED25519_PRIV_FILENAME "/data/dropbear/dropbear_ed25519_host_key"

#define DROPBEAR_PIDFILE "/data/dropbear/dropbear.pid"

// android root may has the home folder as /
// change the cli auth key path
#define DROPBEAR_DEFAULT_CLI_AUTHKEY "/data/dropbear/.ssh/id_dropbear"

// commonly android does not has a sftp-server out of box
#define DROPBEAR_SFTPSERVER 0

// define the default path
#define DEFAULT_ROOT_PATH "/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin"

src/svr-authpubkey.c:

// change authorized_keys path
static int checkpubkey(const char *keyalgo, unsigned int keyalgolen, const unsigned char *keyblob, unsigned int keybloblen) {
  // ...
  // filename = m_malloc(len + 22);
  // snprintf(filename, len + 22, "%s/.ssh/authorized_keys", ses.authstate.pw_dir);
  char authkeys_filename[] = "/data/dropbear/authorized_keys";
  filename = m_malloc(sizeof(authkeys_filename));
  strcpy(filename, authkeys_filename);
  // ...
}

// do not check public key perms
// as the home for root is /
static int checkpubkeyperms() {
  return DROPBEAR_SUCCESS;
}

localoptions.h:

/*
 * Copyright © 2020-2022 Matt Robinson
 *
 * SPDX-License-Identifier: MIT
 */

// Disable server password auth as crypt() isn't available under Android
#define DROPBEAR_SVR_PASSWORD_AUTH 0

// Disable client password auth as getpass() isn't available under Android
#define DROPBEAR_CLI_PASSWORD_AUTH 0

// Speed up symmetrical ciphers and hashes at the expense of larger binaries
#define DROPBEAR_SMALL_CODE 0

// Build all but the most verbose level of trace messages into the binaries
#define DEBUG_TRACE 4

// Change the fallback list of shells to the non-standard Android shell path
#define COMPAT_USER_SHELLS "/system/bin/sh"

Configure the build:

./configure \
  --host=armv7a-linux-androideabi \
  --disable-utmp \
  --disable-wtmp \
  --disable-utmpx \
  --disable-zlib \
  --disable-syslog \
  AR=llvm-ar \
  CC=armv7a-linux-androideabi23-clang \
  RANLIB=llvm-ranlib \
  STRIP=llvm-sstrip

make PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" SCPPROGRESS=1

Set up on Android

In my case, the device SELinux status is permissive, which often is NOT the case for production builds, so the following may not work for your device.

Check if dropbear works with:

./dropbear -F -R

Auto run needs a new init.rc file in /etc/init, in my case /system is a ext4 partition.

mount -t ext4 -o rw,remount /system
cat > /system/etc/init/dropbear.rc << EOF
service sshd /system/xbin/dropbear
  seclabel u:r:init:s0
  user root
  group root
  oneshot
  disabled

on property:sys.boot_completed=1
    start sshd

EOF
chmod 644 /system/etc/init/dropbear.rc

Refs: