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

Commit d54b70c8 authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Refactor hid command, mitigate overflows

Currently there are a few overflows possible in the hid command by
sending malformed json requests. Refactor the code to avoid these
overflows. These are mostly memcpy usage, where the size comes
(indirectly) from the size of the json array.
The json array must still be valid, because invalid json will produce an
earlier exception in the java layer.

Test: hid malformed_commands.json
The file "malformed_commands.json" can be found in the bug.
Bug: 111363077

Change-Id: I2f9dd31e0bfa2badc58779f40f4a80e025754cd2
parent c0ba1b5f
Loading
Loading
Loading
Loading
+29 −22
Original line number Original line Diff line number Diff line
@@ -42,7 +42,6 @@ namespace android {
namespace uhid {
namespace uhid {


static const char* UHID_PATH = "/dev/uhid";
static const char* UHID_PATH = "/dev/uhid";
static const size_t UHID_MAX_NAME_LENGTH = 128;


static struct {
static struct {
    jmethodID onDeviceOpen;
    jmethodID onDeviceOpen;
@@ -90,8 +89,13 @@ JNIEnv* DeviceCallback::getJNIEnv() {
}
}


Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
        std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
        std::vector<uint8_t> descriptor, std::unique_ptr<DeviceCallback> callback) {
        std::unique_ptr<DeviceCallback> callback) {

    size_t size = descriptor.size();
    if (size > HID_MAX_DESCRIPTOR_SIZE) {
        LOGE("Received invalid hid report with descriptor size %zu, skipping", size);
        return nullptr;
    }


    int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC);
    int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC);
    if (fd < 0) {
    if (fd < 0) {
@@ -102,10 +106,10 @@ Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
    struct uhid_event ev;
    struct uhid_event ev;
    memset(&ev, 0, sizeof(ev));
    memset(&ev, 0, sizeof(ev));
    ev.type = UHID_CREATE2;
    ev.type = UHID_CREATE2;
    strncpy((char*)ev.u.create2.name, name, UHID_MAX_NAME_LENGTH);
    strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name));
    memcpy(&ev.u.create2.rd_data, descriptor.get(),
    memcpy(&ev.u.create2.rd_data, descriptor.data(),
            descriptorSize * sizeof(ev.u.create2.rd_data[0]));
            size * sizeof(ev.u.create2.rd_data[0]));
    ev.u.create2.rd_size = descriptorSize;
    ev.u.create2.rd_size = size;
    ev.u.create2.bus = BUS_BLUETOOTH;
    ev.u.create2.bus = BUS_BLUETOOTH;
    ev.u.create2.vendor = vid;
    ev.u.create2.vendor = vid;
    ev.u.create2.product = pid;
    ev.u.create2.product = pid;
@@ -156,12 +160,17 @@ Device::~Device() {
    mFd = -1;
    mFd = -1;
}
}


void Device::sendReport(uint8_t* report, size_t reportSize) {
void Device::sendReport(const std::vector<uint8_t>& report) const {
    if (report.size() > UHID_DATA_MAX) {
        LOGE("Received invalid report of size %zu, skipping", report.size());
        return;
    }

    struct uhid_event ev;
    struct uhid_event ev;
    memset(&ev, 0, sizeof(ev));
    memset(&ev, 0, sizeof(ev));
    ev.type = UHID_INPUT2;
    ev.type = UHID_INPUT2;
    ev.u.input2.size = reportSize;
    ev.u.input2.size = report.size();
    memcpy(&ev.u.input2.data, report, reportSize);
    memcpy(&ev.u.input2.data, report.data(), report.size() * sizeof(ev.u.input2.data[0]));
    ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
    ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
    if (ret < 0 || ret != sizeof(ev)) {
    if (ret < 0 || ret != sizeof(ev)) {
        LOGE("Failed to send hid event: %s", strerror(errno));
        LOGE("Failed to send hid event: %s", strerror(errno));
@@ -191,12 +200,13 @@ int Device::handleEvents(int events) {


} // namespace uhid
} // namespace uhid


std::unique_ptr<uint8_t[]> getData(JNIEnv* env, jbyteArray javaArray, size_t& outSize) {
std::vector<uint8_t> getData(JNIEnv* env, jbyteArray javaArray) {
    ScopedByteArrayRO scopedArray(env, javaArray);
    ScopedByteArrayRO scopedArray(env, javaArray);
    outSize = scopedArray.size();
    size_t size = scopedArray.size();
    std::unique_ptr<uint8_t[]> data(new uint8_t[outSize]);
    std::vector<uint8_t> data;
    for (size_t i = 0; i < outSize; i++) {
    data.reserve(size);
        data[i] = static_cast<uint8_t>(scopedArray[i]);
    for (size_t i = 0; i < size; i++) {
        data.push_back(static_cast<uint8_t>(scopedArray[i]));
    }
    }
    return data;
    return data;
}
}
@@ -208,23 +218,20 @@ static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint i
        return 0;
        return 0;
    }
    }


    size_t size;
    std::vector<uint8_t> desc = getData(env, rawDescriptor);
    std::unique_ptr<uint8_t[]> desc = getData(env, rawDescriptor, size);


    std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
    std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));


    uhid::Device* d = uhid::Device::open(
    uhid::Device* d = uhid::Device::open(
            id, reinterpret_cast<const char*>(name.c_str()), vid, pid,
            id, reinterpret_cast<const char*>(name.c_str()), vid, pid, desc, std::move(cb));
            std::move(desc), size, std::move(cb));
    return reinterpret_cast<jlong>(d);
    return reinterpret_cast<jlong>(d);
}
}


static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) {
static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) {
    size_t size;
    std::vector<uint8_t> report = getData(env, rawReport);
    std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size);
    uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
    uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
    if (d) {
    if (d) {
        d->sendReport(report.get(), size);
        d->sendReport(report);
    } else {
    } else {
        LOGE("Could not send report, Device* is null!");
        LOGE("Could not send report, Device* is null!");
    }
    }
+3 −3
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
 */
 */


#include <memory>
#include <memory>
#include <vector>


#include <jni.h>
#include <jni.h>


@@ -38,13 +39,12 @@ private:
class Device {
class Device {
public:
public:
    static Device* open(int32_t id, const char* name, int32_t vid, int32_t pid,
    static Device* open(int32_t id, const char* name, int32_t vid, int32_t pid,
            std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
            std::vector<uint8_t> descriptor, std::unique_ptr<DeviceCallback> callback);
            std::unique_ptr<DeviceCallback> callback);


    Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback);
    Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback);
    ~Device();
    ~Device();


    void sendReport(uint8_t* report, size_t reportSize);
    void sendReport(const std::vector<uint8_t>& report) const;
    void close();
    void close();


    int handleEvents(int events);
    int handleEvents(int events);