OSDN Git Service

Merge "diag: Prevent out-of-bound access while processing dci transaction"
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / char / diag / diag_dci.c
index b0b36d0..aedeeef 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -984,7 +984,7 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source,
        int save_req_uid = 0;
        struct diag_dci_pkt_rsp_header_t pkt_rsp_header;
 
-       if (!buf) {
+       if (!buf || len <= 0) {
                pr_err("diag: Invalid pointer in %s\n", __func__);
                return;
        }
@@ -998,6 +998,8 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source,
                                                                dci_cmd_code);
                return;
        }
+       if (len < (cmd_code_len + sizeof(int)))
+               return;
        temp += cmd_code_len;
        tag = *(int *)temp;
        temp += sizeof(int);
@@ -1006,10 +1008,16 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source,
         * The size of the response is (total length) - (length of the command
         * code, the tag (int)
         */
-       rsp_len = len - (cmd_code_len + sizeof(int));
-       if ((rsp_len == 0) || (rsp_len > (len - 5))) {
-               pr_err("diag: Invalid length in %s, len: %d, rsp_len: %d",
-                                               __func__, len, rsp_len);
+       if (len >= cmd_code_len + sizeof(int)) {
+               rsp_len = len - (cmd_code_len + sizeof(int));
+               if ((rsp_len == 0) || (rsp_len > (len - 5))) {
+                       pr_err("diag: Invalid length in %s, len: %d, rsp_len: %d\n",
+                                       __func__, len, rsp_len);
+                       return;
+               }
+       } else {
+               pr_err("diag:%s: Invalid length(%d) for calculating rsp_len\n",
+                       __func__, len);
                return;
        }
 
@@ -1537,6 +1545,7 @@ void diag_dci_notify_client(int peripheral_mask, int data, int proc)
                                        DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
                                                "diag: dci client with pid = %d Exited..\n",
                                                entry->tgid);
+                                       put_pid(pid_struct);
                                        mutex_unlock(&driver->dci_mutex);
                                        return;
                                }
@@ -1551,9 +1560,12 @@ void diag_dci_notify_client(int peripheral_mask, int data, int proc)
                                        if (stat)
                                                pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n",
                                                        info.si_int, stat);
-                               } else
+                               } else {
                                        pr_err("diag: client data is corrupted, signal data: 0x%x, stat: %d\n",
                                                info.si_int, stat);
+                               }
+                               put_task_struct(dci_task);
+                               put_pid(pid_struct);
                        }
                }
        }
@@ -1935,7 +1947,9 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
        if (!buf)
                return -EIO;
 
-       if (len <= sizeof(struct dci_pkt_req_t) || len > DCI_REQ_BUF_SIZE) {
+       if (len <= (sizeof(struct dci_pkt_req_t) +
+               sizeof(struct diag_pkt_header_t)) ||
+               len > DCI_REQ_BUF_SIZE) {
                pr_err("diag: dci: Invalid length %d len in %s", len, __func__);
                return -EIO;
        }
@@ -2058,9 +2072,9 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
        uint8_t *event_mask_ptr;
        struct diag_dci_client_tbl *dci_entry = NULL;
 
-       if (!temp) {
-               pr_err("diag: Invalid buffer in %s\n", __func__);
-               return -ENOMEM;
+       if (!temp || len < sizeof(int)) {
+               pr_err("diag: Invalid input in %s\n", __func__);
+               return -EINVAL;
        }
 
        /* This is Pkt request/response transaction */
@@ -2115,7 +2129,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
                count = 0; /* iterator for extracting log codes */
 
                while (count < num_codes) {
-                       if (read_len >= USER_SPACE_DATA) {
+                       if (read_len + sizeof(uint16_t) > len) {
                                pr_err("diag: dci: Invalid length for log type in %s",
                                                                __func__);
                                mutex_unlock(&driver->dci_mutex);
@@ -2228,7 +2242,7 @@ int diag_process_dci_transaction(unsigned char *buf, int len)
                pr_debug("diag: head of dci event mask %pK\n", event_mask_ptr);
                count = 0; /* iterator for extracting log codes */
                while (count < num_codes) {
-                       if (read_len >= USER_SPACE_DATA) {
+                       if (read_len + sizeof(int) > len) {
                                pr_err("diag: dci: Invalid length for event type in %s",
                                                                __func__);
                                mutex_unlock(&driver->dci_mutex);
@@ -2296,8 +2310,8 @@ struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int tgid)
                pid_struct = find_get_pid(entry->tgid);
                if (!pid_struct) {
                        DIAG_LOG(DIAG_DEBUG_DCI,
-                               "diag: valid pid doesn't exist for pid = %d\n",
-                               entry->tgid);
+                       "diag: Exited pid (%d) doesn't match dci client of pid (%d)\n",
+                       tgid, entry->tgid);
                        continue;
                }
                task_s = get_pid_task(pid_struct, PIDTYPE_PID);
@@ -2305,11 +2319,18 @@ struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int tgid)
                        DIAG_LOG(DIAG_DEBUG_DCI,
                                "diag: valid task doesn't exist for pid = %d\n",
                                entry->tgid);
+                       put_pid(pid_struct);
                        continue;
                }
-               if (task_s == entry->client)
-                       if (entry->client->tgid == tgid)
+               if (task_s == entry->client) {
+                       if (entry->client->tgid == tgid) {
+                               put_task_struct(task_s);
+                               put_pid(pid_struct);
                                return entry;
+                       }
+               }
+               put_task_struct(task_s);
+               put_pid(pid_struct);
        }
        return NULL;
 }
@@ -2939,6 +2960,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry)
 
        mutex_lock(&driver->dci_mutex);
 
+       get_task_struct(current);
        new_entry->client = current;
        new_entry->tgid = current->tgid;
        new_entry->client_info.notification_list =
@@ -3085,6 +3107,9 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry)
        if (!list_empty(&entry->track))
                list_del(&entry->track);
        driver->num_dci_client--;
+
+       put_task_struct(entry->client);
+       entry->client = NULL;
        /*
         * Clear the client's log and event masks, update the cumulative
         * masks and send the masks to peripherals