1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define TLOG_TAG "metrics-consumer"
18 #include "consumer.h"
19
20 #include <interface/metrics/consumer.h>
21 #include <lib/tipc/tipc.h>
22 #include <lib/tipc/tipc_srv.h>
23 #include <metrics_consts.h>
24 #include <openssl/sha.h>
25 #include <stddef.h>
26 #include <string.h>
27 #include <trusty_log.h>
28 #include <uapi/err.h>
29
30 /*
31 Current use cases:
32 1) Metrics daemon
33 2) Trusty kernel metrics reporter
34 3) Storage metrics
35 4) Android metrics test
36 */
37 #define MAX_METRICS_TA_CONNECTIONS 4
38
39 static const struct uuid zero_uuid = UUID_INITIAL_VALUE(zero_uuid);
40
is_zero_uuid(const struct uuid * peer)41 static bool is_zero_uuid(const struct uuid* peer) {
42 return equal_uuid(peer, &zero_uuid);
43 }
44
on_connect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)45 static int on_connect(const struct tipc_port* port,
46 handle_t chan,
47 const struct uuid* peer,
48 void** ctx_p) {
49
50 struct srv_state* state = get_srv_state(port);
51 if(is_zero_uuid(peer))
52 {
53 TLOGD("Updating metrics daemon handle :%d\n", chan);
54 if(state->ns_handle != INVALID_IPC_HANDLE) {
55 close(state->ns_handle);
56 }
57 state->ns_handle = chan;
58 }
59
60 return NO_ERROR;
61 }
62
hash_trusty_metrics(uint64_t metric,char * app_id,uint8_t * output)63 void hash_trusty_metrics(uint64_t metric, char *app_id, uint8_t *output) {
64
65 const unsigned char CONST_SALT[] = {
66 0xf2, 0xe7, 0x8c, 0x19, 0xa4, 0xd3, 0x5b, 0x68
67 };
68
69 /* Convert the metric to an array of uint8_t prepended with salt*/
70 uint8_t metric_arr[8 + UUID_STR_SIZE + sizeof(CONST_SALT)];
71
72 memcpy(metric_arr, app_id, UUID_STR_SIZE);
73 memcpy(metric_arr+UUID_STR_SIZE, CONST_SALT, sizeof(CONST_SALT));
74
75 for (size_t i = 0; i < 8; ++i) {
76 metric_arr[i+ UUID_STR_SIZE + sizeof(CONST_SALT)] = (metric >> (8 * i)) & 0xFF;
77 }
78
79 SHA512(metric_arr, sizeof(metric_arr), output);
80 }
81
on_message(const struct tipc_port * port,handle_t chan,void * ctx)82 static int on_message(const struct tipc_port* port, handle_t chan, void* ctx) {
83 int rc;
84 struct metrics_req req;
85 uint8_t msg[METRICS_MAX_MSG_SIZE];
86
87 memset(msg, 0, sizeof(msg));
88 int msg_size = tipc_recv1(chan, sizeof(req), msg, sizeof(msg));
89 if (msg_size < 0) {
90 TLOGE("failed (%d) to receive metrics event\n", msg_size);
91 return msg_size;
92 }
93
94 uint32_t cmd;
95 cmd = ((struct metrics_req*)msg)->cmd;
96
97 if(cmd == METRICS_CMD_REPORT_CRASH) {
98 struct metrics_crash_msg *crash_msg = (struct metrics_crash_msg *)msg;
99 if (crash_msg->crash_args.is_hash) {
100 hash_trusty_metrics(crash_msg->crash_args.far, crash_msg->crash_args.app_id, crash_msg->crash_args.far_hash);
101 hash_trusty_metrics(crash_msg->crash_args.elr, crash_msg->crash_args.app_id, crash_msg->crash_args.elr_hash);
102 crash_msg->crash_args.far = 0;
103 crash_msg->crash_args.elr = 0;
104 }
105 }
106
107 // Check if NS metricsd connected, if so forward it there.
108 struct srv_state* state = get_srv_state(port);
109 if(is_ns_connected(state)) {
110 rc = tipc_send1(state->ns_handle, msg, msg_size);
111 if (rc < 0) {
112 TLOGE("failed (%d) to send metrics event tp NS metricsd\n", rc);
113 return rc;
114 }
115 }
116 else {
117 TLOGD("NS metrics daemon not connected\n");
118 }
119
120 struct metrics_resp resp = {
121 .cmd = (cmd | METRICS_CMD_RESP_BIT)
122 };
123
124 rc = tipc_send1(chan, &resp, sizeof(resp));
125 if (rc < 0) {
126 TLOGE("failed (%d) to send metrics event response\n", rc);
127 return rc;
128 }
129
130 if ((size_t)rc != sizeof(resp)) {
131 TLOGE("unexpected number of bytes sent: %d\n", rc);
132 return ERR_BAD_LEN;
133 }
134
135 return NO_ERROR;
136 }
137
add_metrics_consumer_service(struct tipc_hset * hset,struct srv_state * state)138 int add_metrics_consumer_service(struct tipc_hset* hset, struct srv_state* state) {
139 static struct tipc_port_acl port_acl = {
140 .flags = IPC_PORT_ALLOW_TA_CONNECT | IPC_PORT_ALLOW_NS_CONNECT,
141 };
142 static struct tipc_port port = {
143 .name = METRICS_CONSUMER_PORT,
144 .msg_max_size = METRICS_MAX_MSG_SIZE,
145 .msg_queue_len = 1,
146 .acl = &port_acl,
147 };
148 static struct tipc_srv_ops ops = {
149 .on_message = on_message,
150 .on_connect = on_connect,
151 };
152 set_srv_state(&port, state);
153
154 return tipc_add_service(hset, &port, 1, MAX_METRICS_TA_CONNECTIONS, &ops);
155 }