blob: 63262a0d0102a81d5a7f1901fe2fe442d78d794a [file] [log] [blame]
Michael Ryleev0a72ad92015-07-22 18:21:10 -07001/*
Matthew Maurere251fa32020-06-15 14:08:55 -07002 * Copyright (C) 2020 The Android Open Source Project
Michael Ryleev0a72ad92015-07-22 18:21:10 -07003 *
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 LOG_TAG "libtrusty"
18
19#include <errno.h>
20#include <fcntl.h>
21#include <stdbool.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
Mark Salyzyncfd5b082016-10-17 14:28:00 -070025#include <sys/ioctl.h>
Arve Hjønnevågd5359ab2023-09-08 14:32:12 -070026#include <sys/socket.h>
27#include <sys/uio.h>
Mark Salyzyncfd5b082016-10-17 14:28:00 -070028#include <unistd.h>
Michael Ryleev0a72ad92015-07-22 18:21:10 -070029
Arve Hjønnevågd5359ab2023-09-08 14:32:12 -070030#include <linux/vm_sockets.h> /* must be after sys/socket.h */
Mark Salyzyn30f991f2017-01-10 13:19:54 -080031#include <log/log.h>
Michael Ryleev0a72ad92015-07-22 18:21:10 -070032
Matthew Maurere251fa32020-06-15 14:08:55 -070033#include <trusty/ipc.h>
Michael Ryleev0a72ad92015-07-22 18:21:10 -070034
Arve Hjønnevågd5359ab2023-09-08 14:32:12 -070035static const char* strip_prefix(const char* str, const char* prefix) {
36 size_t prefix_len = strlen(prefix);
37 if (strncmp(str, prefix, prefix_len) == 0) {
38 return str + prefix_len;
39 } else {
40 return NULL;
41 }
42}
43
44static bool use_vsock_connection = false;
45static int tipc_vsock_connect(const char* type_cid_port_str, const char* srv_name) {
46 int ret;
47 const char* cid_port_str;
48 char* port_str;
49 char* end_str;
50 int socket_type;
51 if ((cid_port_str = strip_prefix(type_cid_port_str, "STREAM:"))) {
52 socket_type = SOCK_STREAM;
53 } else if ((cid_port_str = strip_prefix(type_cid_port_str, "SEQPACKET:"))) {
54 socket_type = SOCK_SEQPACKET;
55 } else {
56 /*
57 * Default to SOCK_STREAM if neither type is specified.
58 *
59 * TODO: use SOCK_SEQPACKET by default instead of SOCK_STREAM when SOCK_SEQPACKET is fully
60 * supported since it matches tipc better. At the moment SOCK_SEQPACKET is not supported by
61 * crosvm. It is also significantly slower since the Linux kernel implementation (as of
62 * v6.7-rc1) sends credit update packets every time it receives a data packet while the
63 * SOCK_STREAM version skips these unless the remaining buffer space is "low".
64 */
65 socket_type = SOCK_STREAM;
66 cid_port_str = type_cid_port_str;
67 }
68 long cid = strtol(cid_port_str, &port_str, 0);
69 if (port_str[0] != ':') {
70 ALOGE("%s: invalid VSOCK str, \"%s\", need cid:port missing : after cid\n", __func__,
71 cid_port_str);
72 return -EINVAL;
73 }
74 long port = strtol(port_str + 1, &end_str, 0);
75 if (end_str[0] != '\0') {
76 ALOGE("%s: invalid VSOCK str, \"%s\", need cid:port got %ld:%ld\n", __func__, cid_port_str,
77 cid, port);
78 return -EINVAL;
79 }
80 int fd = socket(AF_VSOCK, socket_type, 0);
81 if (fd < 0) {
82 ret = -errno;
83 ALOGE("%s: can't get vsock %ld:%ld socket for tipc service \"%s\" (err=%d)\n", __func__,
84 cid, port, srv_name, errno);
85 return ret < 0 ? ret : -1;
86 }
87 struct timeval connect_timeout = {.tv_sec = 60, .tv_usec = 0};
88 ret = setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_CONNECT_TIMEOUT, &connect_timeout,
89 sizeof(connect_timeout));
90 if (ret) {
91 ALOGE("%s: vsock %ld:%ld: Failed to set connect timeout (err=%d)\n", __func__, cid, port,
92 errno);
93 /* failed to set longer timeout, but try to connect anyway */
94 }
95 struct sockaddr_vm sa = {
96 .svm_family = AF_VSOCK,
97 .svm_port = port,
98 .svm_cid = cid,
99 };
100 int retry = 10;
101 do {
102 ret = TEMP_FAILURE_RETRY(connect(fd, (struct sockaddr*)&sa, sizeof(sa)));
103 if (ret && (errno == ENODEV || errno == ESOCKTNOSUPPORT) && --retry) {
104 /*
105 * The kernel returns ESOCKTNOSUPPORT instead of ENODEV if the socket type is
106 * SOCK_SEQPACKET and the guest CID we are trying to connect to is not ready yet.
107 */
108 ALOGE("%s: Can't connect to vsock %ld:%ld for tipc service \"%s\" (err=%d) %d retries "
109 "remaining\n",
110 __func__, cid, port, srv_name, errno, retry);
111 sleep(1);
112 } else {
113 retry = 0;
114 }
115 } while (retry);
116 if (ret) {
117 ret = -errno;
118 ALOGE("%s: Can't connect to vsock %ld:%ld for tipc service \"%s\" (err=%d)\n", __func__,
119 cid, port, srv_name, errno);
120 close(fd);
121 return ret < 0 ? ret : -1;
122 }
123 /*
124 * TODO: Current vsock tipc bridge in trusty expects a port name in the
125 * first packet. We need to replace this with a protocol that also does DICE
126 * based authentication.
127 */
128 ret = TEMP_FAILURE_RETRY(write(fd, srv_name, strlen(srv_name)));
129 if (ret != strlen(srv_name)) {
130 ret = -errno;
131 ALOGE("%s: vsock %ld:%ld: failed to send tipc service name \"%s\" (err=%d)\n", __func__,
132 cid, port, srv_name, errno);
133 close(fd);
134 return ret < 0 ? ret : -1;
135 }
136 /*
137 * Work around lack of seq packet support. Read a status byte to prevent
138 * the caller from sending more data until srv_name has been read.
139 */
140 int8_t status;
141 ret = TEMP_FAILURE_RETRY(read(fd, &status, sizeof(status)));
142 if (ret != sizeof(status)) {
143 ALOGE("%s: vsock %ld:%ld: failed to read status byte for connect to tipc service name "
144 "\"%s\" (err=%d)\n",
145 __func__, cid, port, srv_name, errno);
146 close(fd);
147 return ret < 0 ? ret : -1;
148 }
149 use_vsock_connection = true;
150 return fd;
151}
152
153static size_t tipc_vsock_send(int fd, const struct iovec* iov, int iovcnt, struct trusty_shm* shms,
154 int shmcnt) {
155 int ret;
156
157 (void)shms;
158 if (shmcnt != 0) {
159 ALOGE("%s: vsock does not yet support passing fds\n", __func__);
160 return -ENOTSUP;
161 }
162 ret = TEMP_FAILURE_RETRY(writev(fd, iov, iovcnt));
163 if (ret < 0) {
164 ret = -errno;
165 ALOGE("%s: failed to send message (err=%d)\n", __func__, errno);
166 return ret < 0 ? ret : -1;
167 }
168
169 return ret;
170}
171
Tri Vob47dbe72020-11-17 19:39:36 -0800172int tipc_connect(const char* dev_name, const char* srv_name) {
173 int fd;
174 int rc;
Michael Ryleev0a72ad92015-07-22 18:21:10 -0700175
Arve Hjønnevågd5359ab2023-09-08 14:32:12 -0700176 const char* type_cid_port_str = strip_prefix(dev_name, "VSOCK:");
177 if (type_cid_port_str) {
178 return tipc_vsock_connect(type_cid_port_str, srv_name);
179 }
180
Tri Vo27b0b3f2020-11-17 19:41:57 -0800181 fd = TEMP_FAILURE_RETRY(open(dev_name, O_RDWR));
Tri Vob47dbe72020-11-17 19:39:36 -0800182 if (fd < 0) {
183 rc = -errno;
184 ALOGE("%s: cannot open tipc device \"%s\": %s\n", __func__, dev_name, strerror(errno));
185 return rc < 0 ? rc : -1;
186 }
Michael Ryleev0a72ad92015-07-22 18:21:10 -0700187
Tri Vo27b0b3f2020-11-17 19:41:57 -0800188 rc = TEMP_FAILURE_RETRY(ioctl(fd, TIPC_IOC_CONNECT, srv_name));
Tri Vob47dbe72020-11-17 19:39:36 -0800189 if (rc < 0) {
190 rc = -errno;
191 ALOGE("%s: can't connect to tipc service \"%s\" (err=%d)\n", __func__, srv_name, errno);
192 close(fd);
193 return rc < 0 ? rc : -1;
194 }
Michael Ryleev0a72ad92015-07-22 18:21:10 -0700195
Tri Vob47dbe72020-11-17 19:39:36 -0800196 ALOGV("%s: connected to \"%s\" fd %d\n", __func__, srv_name, fd);
197 return fd;
Michael Ryleev0a72ad92015-07-22 18:21:10 -0700198}
199
Matthew Maurere251fa32020-06-15 14:08:55 -0700200ssize_t tipc_send(int fd, const struct iovec* iov, int iovcnt, struct trusty_shm* shms,
201 int shmcnt) {
Arve Hjønnevågd5359ab2023-09-08 14:32:12 -0700202 if (use_vsock_connection) {
203 return tipc_vsock_send(fd, iov, iovcnt, shms, shmcnt);
204 }
Matthew Maurere251fa32020-06-15 14:08:55 -0700205 struct tipc_send_msg_req req;
206 req.iov = (__u64)iov;
207 req.iov_cnt = (__u64)iovcnt;
208 req.shm = (__u64)shms;
209 req.shm_cnt = (__u64)shmcnt;
210
Tri Vo27b0b3f2020-11-17 19:41:57 -0800211 int rc = TEMP_FAILURE_RETRY(ioctl(fd, TIPC_IOC_SEND_MSG, &req));
Matthew Maurere251fa32020-06-15 14:08:55 -0700212 if (rc < 0) {
213 ALOGE("%s: failed to send message (err=%d)\n", __func__, rc);
214 }
215
216 return rc;
217}
218
Tri Vob47dbe72020-11-17 19:39:36 -0800219void tipc_close(int fd) {
220 close(fd);
Michael Ryleev0a72ad92015-07-22 18:21:10 -0700221}