0

I'm building a POC Android app that needs to communicate with an ELF binary over a Unix domain socket server that the binary binds to and listens on. The app is meant for rooted phones and executes the binary as a superuser upon launch. I need to connect with the binary from my client residing in native code, which I'm presently failing to do.

I'm using a self-ported, stripped down version of libsocket to implement the domain socket functionality for both the binary and the Android app (through JNI). The binary communicates perfectly with a command line client, however, it fails to connect with the client that I've implemented in JNI code. I've made sure that the binary is running from /data/data/<my_package_name>/files and that the server socket has public access (777).

While researching the above problem, I stumbled across the fact that NDK requires LocalSockets to be in the Linux abstract namespace. My server (arm binary) binds to an absolute path (/data/data/<my_package_name>/files/serversocket) as libsocket does not support the abstract namespace for unix domain sockets (due to the usage of strlen() and strncopy() which do not support strings beginning with \0).

The following is the code for create_socket from libsocket that's failing with a negative fd.

int create_socket(const char* path, int flags) {
    if (path == NULL) {
        return -1;
    }
    if (strlen(path) > sizeof(((struct sockaddr_un*) 0)->sun_path) - 1) {
        return -1;
    }

    int fd = socket(AF_LOCAL, SOCK_STREAM | flags, 0);
    if (fd < 0) {
        return -1;
    }

    struct sockaddr_un addr;
    memset(&addr, 0, sizeof(addr));

    addr.sun_family = AF_LOCAL;
    strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);

   // the connect call below fails, errno is set to 13 (EACCESS)

    if (connect(fd, (struct sockaddr*) &addr, sizeof(addr.sun_family) + strlen(addr.sun_path))) {
        close(fd);
        return -1;
    }
    return fd;
}

EDIT : In the above code, the call to connect() fails, with errno being set to 13 (EACCESS). This seems to be an insufficient privileges problem.

I'm wondering if there's any way for me to connect my client to an absolute path from within NDK. It works just fine when I package the client in an ELF executable that runs as superuser, am I missing something obvious here?

Sourav Banerjee
  • 191
  • 2
  • 8
  • "failing with a negative fd" What fails? socket() or connect()? What does connect() return? If connect() is failing, what is the value of `errno`? – Jim Rhodes Oct 22 '19 at 12:46
  • Thanks for your reply. The call to connect() fails with errno being set to 13 (EACCESS). Insufficient privileges seem to be a problem here. As of now, I am launching the binary separately, can different UID's for the client and server be a problem? – Sourav Banerjee Oct 22 '19 at 13:53
  • *can different UID's for the client and server be a problem?* Of course. What's the permissions on **all** the directories in the path to the socket? – Andrew Henle Oct 22 '19 at 16:54
  • 1
    @AndrewHenle both the socket and the binary that listens on it are located in /data/data//files, a directory that my app can rwx from. Executing the binary as root causes the socket pseudo file to automatically assume root:root uid and gid, which is why I couldn't connect despite the binary itself having proper permissions. Manually setting the uid and gid back to the app user (u0_a273 for my app) lets me connect to the server, however, I am unable to send any data across (the server doesn't pick up any and exits the handler). I'm still debugging this :( – Sourav Banerjee Oct 22 '19 at 17:47

1 Answers1

1

To anyone who might be following this, it is necessary to set appropriate permissions on the socket pseudo file manually every time it is launched as root, else connect() fails with errno being set to EACCESS. I'm yet to find a better solution to this.

Sourav Banerjee
  • 191
  • 2
  • 8