Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 63ee5bbf authored by Orion Hodson's avatar Orion Hodson
Browse files

Avoid potential fd leaks from jniCreateFileDescriptor (2/2)

Fixes corner case leaks in JNI code under com.android.server.

Bug: 155706035
Test: m
Change-Id: I5b3a79911a33a0e04c019943c438a433cf04465b
parent e15bd916
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ static jobject android_server_SerialService_open(JNIEnv *env, jobject /* thiz */

    jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
    if (fileDescriptor == NULL) {
        close(fd);
        return NULL;
    }
    return env->NewObject(gParcelFileDescriptorOffsets.mClass,
+13 −16
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
#include "MtpDescriptors.h"
@@ -88,6 +89,7 @@ static jobject android_server_UsbDeviceManager_openAccessory(JNIEnv *env, jobjec
    }
    jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
    if (fileDescriptor == NULL) {
        close(fd);
        return NULL;
    }
    return env->NewObject(gParcelFileDescriptorOffsets.mClass,
@@ -120,35 +122,30 @@ static jint android_server_UsbDeviceManager_getAudioMode(JNIEnv* /* env */, jobj
}

static jobject android_server_UsbDeviceManager_openControl(JNIEnv *env, jobject /* thiz */, jstring jFunction) {
    const char *function = env->GetStringUTFChars(jFunction, NULL);
    ScopedUtfChars function(env, jFunction);
    bool ptp = false;
    int fd = -1;
    if (!strcmp(function, "ptp")) {
    if (!strcmp(function.c_str(), "ptp")) {
        ptp = true;
    }
    if (!strcmp(function, "mtp") || ptp) {
    if (!strcmp(function.c_str(), "mtp") || ptp) {
        fd = TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP0 : FFS_MTP_EP0, O_RDWR));
        if (fd < 0) {
            ALOGE("could not open control for %s %s", function, strerror(errno));
            goto error;
            ALOGE("could not open control for %s %s", function.c_str(), strerror(errno));
            return NULL;
        }
        if (!writeDescriptors(fd, ptp)) {
            goto error;
            close(fd);
            return NULL;
        }
    }

    if (function != NULL) {
        env->ReleaseStringUTFChars(jFunction, function);
    }
    return jniCreateFileDescriptor(env, fd);
error:
    if (fd != -1) {
    jobject jifd = jniCreateFileDescriptor(env, fd);
    if (jifd == NULL) {
        // OutOfMemoryError will be pending.
        close(fd);
    }
    if (function != NULL) {
        env->ReleaseStringUTFChars(jFunction, function);
    }
    return NULL;
    return jifd;
}

static const JNINativeMethod method_table[] = {
+1 −0
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /*

    jobject fileDescriptor = jniCreateFileDescriptor(env, newFD);
    if (fileDescriptor == NULL) {
        close(newFD);
        return NULL;
    }
    return env->NewObject(gParcelFileDescriptorOffsets.mClass,
+34 −12
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@

#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"

@@ -99,24 +100,45 @@ android_server_UsbMidiDevice_open(JNIEnv *env, jobject thiz, jint card, jint dev
        int fd = open(path, O_RDWR);
        if (fd < 0) {
            ALOGE("open failed on %s for index %d", path, i);
            return NULL;
            goto release_fds;
        }

        jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
        env->SetObjectArrayElement(fds, i, fileDescriptor);
        env->DeleteLocalRef(fileDescriptor);
        ScopedLocalRef<jobject> jifd(env, jniCreateFileDescriptor(env, fd));
        if (jifd.get() == NULL) {
            goto release_fds;
        }
        env->SetObjectArrayElement(fds, i, jifd.get());
    }

    // create a pipe to use for unblocking our input thread
    {
        int pipeFD[2];
    pipe(pipeFD);
    jobject fileDescriptor = jniCreateFileDescriptor(env, pipeFD[0]);
    env->SetObjectArrayElement(fds, subdevice_count, fileDescriptor);
    env->DeleteLocalRef(fileDescriptor);
        if (pipe(pipeFD) == -1) {
            ALOGE("pipe() failed, errno = %d", errno);
            goto release_fds;
        }

        ScopedLocalRef<jobject> jifd(env, jniCreateFileDescriptor(env, pipeFD[0]));
        if (jifd.get() == NULL) {
            close(pipeFD[0]);
            close(pipeFD[1]);
            goto release_fds;
        }
        env->SetObjectArrayElement(fds, subdevice_count, jifd.get());
        // store our end of the pipe in mPipeFD
        env->SetIntField(thiz, sPipeFDField, pipeFD[1]);

    }
    return fds;

release_fds:
    for (int i = 0; i < subdevice_count + 1; ++i) {
        ScopedLocalRef<jobject> jifd(env, env->GetObjectArrayElement(fds, i));
        if (jifd.get() == NULL) {
            break;
        }
        int fd = jniGetFDFromFileDescriptor(env, jifd.get());
        close(fd);
    }
    return NULL;
}

static void