1 /*-
2 * Copyright (c) 2015 iXsystems Inc.
3 * Copyright (c) 2017-2018 Jakub Klama <jceel@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer
11 * in this position and unchanged.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * VirtIO filesystem passthrough using 9p protocol.
31 */
32
33
34 #include <sys/param.h>
35 #include <sys/linker_set.h>
36 #include <sys/uio.h>
37 #ifndef WITHOUT_CAPSICUM
38 #include <sys/capsicum.h>
39 #endif
40
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <assert.h>
48 #include <pthread.h>
49
50 #include <lib9p.h>
51 #include <backend/fs.h>
52
53 #include "bhyverun.h"
54 #include "config.h"
55 #include "debug.h"
56 #include "pci_emul.h"
57 #include "virtio.h"
58
59 #ifndef __FreeBSD__
60 #include "privileges.h"
61 #endif
62
63 #define VT9P_MAX_IOV 128
64 #define VT9P_RINGSZ 256
65 #define VT9P_MAXTAGSZ 256
66 #define VT9P_CONFIGSPACESZ (VT9P_MAXTAGSZ + sizeof(uint16_t))
67
68 static int pci_vt9p_debug;
69 #define DPRINTF(params) if (pci_vt9p_debug) printf params
70 #define WPRINTF(params) printf params
71
72 /*
73 * Per-device softc
74 */
75 struct pci_vt9p_softc {
76 struct virtio_softc vsc_vs;
77 struct vqueue_info vsc_vq;
78 pthread_mutex_t vsc_mtx;
79 uint64_t vsc_cfg;
80 uint64_t vsc_features;
81 char * vsc_rootpath;
82 struct pci_vt9p_config * vsc_config;
83 struct l9p_backend * vsc_fs_backend;
84 struct l9p_server * vsc_server;
85 struct l9p_connection * vsc_conn;
86 };
87
88 struct pci_vt9p_request {
89 struct pci_vt9p_softc * vsr_sc;
90 struct iovec * vsr_iov;
91 size_t vsr_niov;
92 size_t vsr_respidx;
93 size_t vsr_iolen;
94 uint16_t vsr_idx;
95 };
96
97 struct pci_vt9p_config {
98 uint16_t tag_len;
99 #ifdef __FreeBSD__
100 char tag[0];
101 #else
102 char tag[VT9P_MAXTAGSZ];
103 #endif
104 } __attribute__((packed));
105
106 static int pci_vt9p_send(struct l9p_request *, const struct iovec *,
107 const size_t, const size_t, void *);
108 static void pci_vt9p_drop(struct l9p_request *, const struct iovec *, size_t,
109 void *);
110 static void pci_vt9p_reset(void *);
111 static void pci_vt9p_notify(void *, struct vqueue_info *);
112 static int pci_vt9p_cfgread(void *, int, int, uint32_t *);
113 static void pci_vt9p_neg_features(void *, uint64_t);
114
115 static struct virtio_consts vt9p_vi_consts = {
116 .vc_name = "vt9p",
117 .vc_nvq = 1,
118 .vc_cfgsize = VT9P_CONFIGSPACESZ,
119 .vc_reset = pci_vt9p_reset,
120 .vc_qnotify = pci_vt9p_notify,
121 .vc_cfgread = pci_vt9p_cfgread,
122 .vc_apply_features = pci_vt9p_neg_features,
123 .vc_hv_caps = (1 << 0),
124 };
125
126 static void
pci_vt9p_reset(void * vsc)127 pci_vt9p_reset(void *vsc)
128 {
129 struct pci_vt9p_softc *sc;
130
131 sc = vsc;
132
133 DPRINTF(("vt9p: device reset requested !\n"));
134 vi_reset_dev(&sc->vsc_vs);
135 }
136
137 static void
pci_vt9p_neg_features(void * vsc,uint64_t negotiated_features)138 pci_vt9p_neg_features(void *vsc, uint64_t negotiated_features)
139 {
140 struct pci_vt9p_softc *sc = vsc;
141
142 sc->vsc_features = negotiated_features;
143 }
144
145 static int
pci_vt9p_cfgread(void * vsc,int offset,int size,uint32_t * retval)146 pci_vt9p_cfgread(void *vsc, int offset, int size, uint32_t *retval)
147 {
148 struct pci_vt9p_softc *sc = vsc;
149 void *ptr;
150
151 ptr = (uint8_t *)sc->vsc_config + offset;
152 memcpy(retval, ptr, size);
153 return (0);
154 }
155
156 static int
pci_vt9p_get_buffer(struct l9p_request * req,struct iovec * iov,size_t * niov,void * arg __unused)157 pci_vt9p_get_buffer(struct l9p_request *req, struct iovec *iov, size_t *niov,
158 void *arg __unused)
159 {
160 struct pci_vt9p_request *preq = req->lr_aux;
161 size_t n = preq->vsr_niov - preq->vsr_respidx;
162
163 memcpy(iov, preq->vsr_iov + preq->vsr_respidx,
164 n * sizeof(struct iovec));
165 *niov = n;
166 return (0);
167 }
168
169 static int
pci_vt9p_send(struct l9p_request * req,const struct iovec * iov __unused,const size_t niov __unused,const size_t iolen,void * arg __unused)170 pci_vt9p_send(struct l9p_request *req, const struct iovec *iov __unused,
171 const size_t niov __unused, const size_t iolen, void *arg __unused)
172 {
173 struct pci_vt9p_request *preq = req->lr_aux;
174 struct pci_vt9p_softc *sc = preq->vsr_sc;
175
176 preq->vsr_iolen = iolen;
177
178 pthread_mutex_lock(&sc->vsc_mtx);
179 vq_relchain(&sc->vsc_vq, preq->vsr_idx, preq->vsr_iolen);
180 vq_endchains(&sc->vsc_vq, 1);
181 pthread_mutex_unlock(&sc->vsc_mtx);
182 free(preq);
183 return (0);
184 }
185
186 static void
pci_vt9p_drop(struct l9p_request * req,const struct iovec * iov __unused,size_t niov __unused,void * arg __unused)187 pci_vt9p_drop(struct l9p_request *req, const struct iovec *iov __unused,
188 size_t niov __unused, void *arg __unused)
189 {
190 struct pci_vt9p_request *preq = req->lr_aux;
191 struct pci_vt9p_softc *sc = preq->vsr_sc;
192
193 pthread_mutex_lock(&sc->vsc_mtx);
194 vq_relchain(&sc->vsc_vq, preq->vsr_idx, 0);
195 vq_endchains(&sc->vsc_vq, 1);
196 pthread_mutex_unlock(&sc->vsc_mtx);
197 free(preq);
198 }
199
200 static void
pci_vt9p_notify(void * vsc,struct vqueue_info * vq)201 pci_vt9p_notify(void *vsc, struct vqueue_info *vq)
202 {
203 struct iovec iov[VT9P_MAX_IOV];
204 struct pci_vt9p_softc *sc;
205 struct pci_vt9p_request *preq;
206 struct vi_req req;
207 int n;
208
209 sc = vsc;
210
211 while (vq_has_descs(vq)) {
212 n = vq_getchain(vq, iov, VT9P_MAX_IOV, &req);
213 assert(n >= 1 && n <= VT9P_MAX_IOV);
214 preq = calloc(1, sizeof(struct pci_vt9p_request));
215 #ifndef __FreeBSD__
216 if (preq == NULL) {
217 EPRINTLN("virtio-9p: allocation failure: %s",
218 strerror(errno));
219 break;
220 }
221 #endif
222 preq->vsr_sc = sc;
223 preq->vsr_idx = req.idx;
224 preq->vsr_iov = iov;
225 preq->vsr_niov = n;
226 preq->vsr_respidx = req.readable;
227
228 for (int i = 0; i < n; i++) {
229 DPRINTF(("vt9p: vt9p_notify(): desc%d base=%p, "
230 "len=%zu\r\n", i, iov[i].iov_base,
231 iov[i].iov_len));
232 }
233
234 l9p_connection_recv(sc->vsc_conn, iov, preq->vsr_respidx, preq);
235 }
236 }
237
238 static int
pci_vt9p_legacy_config(nvlist_t * nvl,const char * opts)239 pci_vt9p_legacy_config(nvlist_t *nvl, const char *opts)
240 {
241 char *sharename = NULL, *tofree, *token, *tokens;
242
243 if (opts == NULL)
244 return (0);
245
246 tokens = tofree = strdup(opts);
247 while ((token = strsep(&tokens, ",")) != NULL) {
248 if (strchr(token, '=') != NULL) {
249 if (sharename != NULL) {
250 EPRINTLN(
251 "virtio-9p: more than one share name given");
252 return (-1);
253 }
254
255 sharename = strsep(&token, "=");
256 set_config_value_node(nvl, "sharename", sharename);
257 set_config_value_node(nvl, "path", token);
258 } else
259 set_config_bool_node(nvl, token, true);
260 }
261 free(tofree);
262
263 return (0);
264 }
265
266 static int
pci_vt9p_init(struct pci_devinst * pi,nvlist_t * nvl)267 pci_vt9p_init(struct pci_devinst *pi, nvlist_t *nvl)
268 {
269 struct pci_vt9p_softc *sc;
270 const char *value;
271 const char *sharename;
272 int rootfd;
273 bool ro;
274 #ifndef WITHOUT_CAPSICUM
275 cap_rights_t rootcap;
276 #endif
277
278 ro = get_config_bool_node_default(nvl, "ro", false);
279
280 #ifndef __FreeBSD__
281 illumos_priv_add_min(PRIV_FILE_DAC_READ, "vt9p");
282 illumos_priv_add_min(PRIV_FILE_DAC_SEARCH, "vt9p");
283
284 if (!ro) {
285 illumos_priv_add_min(PRIV_FILE_CHOWN, "vt9p");
286 illumos_priv_add_min(PRIV_FILE_CHOWN_SELF, "vt9p");
287 illumos_priv_add_min(PRIV_FILE_WRITE, "vt9p");
288 illumos_priv_add_min(PRIV_FILE_DAC_WRITE, "vt9p");
289 illumos_priv_add_min(PRIV_FILE_OWNER, "vt9p");
290 illumos_priv_add_min(PRIV_FILE_LINK_ANY, "vt9p");
291 }
292 #endif
293
294 value = get_config_value_node(nvl, "path");
295 if (value == NULL) {
296 EPRINTLN("virtio-9p: path required");
297 return (1);
298 }
299 rootfd = open(value, O_DIRECTORY);
300 if (rootfd < 0) {
301 EPRINTLN("virtio-9p: failed to open '%s': %s", value,
302 strerror(errno));
303 return (-1);
304 }
305
306 sharename = get_config_value_node(nvl, "sharename");
307 if (sharename == NULL) {
308 EPRINTLN("virtio-9p: share name required");
309 return (1);
310 }
311 if (strlen(sharename) > VT9P_MAXTAGSZ) {
312 EPRINTLN("virtio-9p: share name too long");
313 return (1);
314 }
315
316 sc = calloc(1, sizeof(struct pci_vt9p_softc));
317 #ifdef __FreeBSD__
318 sc->vsc_config = calloc(1, sizeof(struct pci_vt9p_config) +
319 VT9P_MAXTAGSZ);
320 #else
321 if (sc == NULL) {
322 EPRINTLN("virtio-9p: soft state allocation failure: %s",
323 strerror(errno));
324 return (1);
325 }
326 sc->vsc_config = calloc(1, sizeof(struct pci_vt9p_config));
327 if (sc == NULL) {
328 EPRINTLN("virtio-9p: vsc_config allocation failure: %s",
329 strerror(errno));
330 return (1);
331 }
332 #endif
333
334 pthread_mutex_init(&sc->vsc_mtx, NULL);
335
336 #ifndef WITHOUT_CAPSICUM
337 cap_rights_init(&rootcap,
338 CAP_LOOKUP, CAP_ACL_CHECK, CAP_ACL_DELETE, CAP_ACL_GET,
339 CAP_ACL_SET, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_FSTAT,
340 CAP_CREATE, CAP_FCHMODAT, CAP_FCHOWNAT, CAP_FTRUNCATE,
341 CAP_LINKAT_SOURCE, CAP_LINKAT_TARGET, CAP_MKDIRAT, CAP_MKNODAT,
342 CAP_PREAD, CAP_PWRITE, CAP_RENAMEAT_SOURCE, CAP_RENAMEAT_TARGET,
343 CAP_SEEK, CAP_SYMLINKAT, CAP_UNLINKAT, CAP_EXTATTR_DELETE,
344 CAP_EXTATTR_GET, CAP_EXTATTR_LIST, CAP_EXTATTR_SET,
345 CAP_FUTIMES, CAP_FSTATFS, CAP_FSYNC, CAP_FPATHCONF);
346
347 if (cap_rights_limit(rootfd, &rootcap) != 0)
348 return (1);
349 #endif
350
351 sc->vsc_config->tag_len = (uint16_t)strlen(sharename);
352 memcpy(sc->vsc_config->tag, sharename, sc->vsc_config->tag_len);
353
354 if (l9p_backend_fs_init(&sc->vsc_fs_backend, rootfd, ro) != 0) {
355 errno = ENXIO;
356 return (1);
357 }
358
359 if (l9p_server_init(&sc->vsc_server, sc->vsc_fs_backend) != 0) {
360 errno = ENXIO;
361 return (1);
362 }
363
364 if (l9p_connection_init(sc->vsc_server, &sc->vsc_conn) != 0) {
365 errno = EIO;
366 return (1);
367 }
368
369 sc->vsc_conn->lc_msize = L9P_MAX_IOV * PAGE_SIZE;
370 sc->vsc_conn->lc_lt.lt_get_response_buffer = pci_vt9p_get_buffer;
371 sc->vsc_conn->lc_lt.lt_send_response = pci_vt9p_send;
372 sc->vsc_conn->lc_lt.lt_drop_response = pci_vt9p_drop;
373
374 vi_softc_linkup(&sc->vsc_vs, &vt9p_vi_consts, sc, pi, &sc->vsc_vq);
375 sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
376 sc->vsc_vq.vq_qsize = VT9P_RINGSZ;
377
378 /* initialize config space */
379 pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_9P);
380 pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
381 pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);
382 pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_9P);
383 pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
384
385 if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))
386 return (1);
387 vi_set_io_bar(&sc->vsc_vs, 0);
388
389 return (0);
390 }
391
392 static const struct pci_devemu pci_de_v9p = {
393 .pe_emu = "virtio-9p",
394 .pe_legacy_config = pci_vt9p_legacy_config,
395 .pe_init = pci_vt9p_init,
396 .pe_barwrite = vi_pci_write,
397 .pe_barread = vi_pci_read
398 };
399 PCI_EMUL_SET(pci_de_v9p);
400