1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * net/9p/protocol.c
4 *
5 * 9P Protocol Support Code
6 *
7 * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
8 *
9 * Base on code from Anthony Liguori <aliguori@us.ibm.com>
10 * Copyright (C) 2008 by IBM, Corp.
11 */
12
13 #include <linux/module.h>
14 #include <linux/errno.h>
15 #include <linux/kernel.h>
16 #include <linux/uaccess.h>
17 #include <linux/slab.h>
18 #include <linux/sched.h>
19 #include <linux/stddef.h>
20 #include <linux/types.h>
21 #include <linux/uio.h>
22 #include <net/9p/9p.h>
23 #include <net/9p/client.h>
24 #include "protocol.h"
25
26 #include <trace/events/9p.h>
27
28 static int
29 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
30
p9stat_free(struct p9_wstat * stbuf)31 void p9stat_free(struct p9_wstat *stbuf)
32 {
33 kfree(stbuf->name);
34 stbuf->name = NULL;
35 kfree(stbuf->uid);
36 stbuf->uid = NULL;
37 kfree(stbuf->gid);
38 stbuf->gid = NULL;
39 kfree(stbuf->muid);
40 stbuf->muid = NULL;
41 kfree(stbuf->extension);
42 stbuf->extension = NULL;
43 }
44 EXPORT_SYMBOL(p9stat_free);
45
pdu_read(struct p9_fcall * pdu,void * data,size_t size)46 size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
47 {
48 size_t len = min(pdu->size - pdu->offset, size);
49
50 memcpy(data, &pdu->sdata[pdu->offset], len);
51 pdu->offset += len;
52 return size - len;
53 }
54
pdu_write(struct p9_fcall * pdu,const void * data,size_t size)55 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
56 {
57 size_t len = min(pdu->capacity - pdu->size, size);
58
59 memcpy(&pdu->sdata[pdu->size], data, len);
60 pdu->size += len;
61 return size - len;
62 }
63
64 static size_t
pdu_write_u(struct p9_fcall * pdu,struct iov_iter * from,size_t size)65 pdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size)
66 {
67 size_t len = min(pdu->capacity - pdu->size, size);
68 struct iov_iter i = *from;
69
70 if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, &i))
71 len = 0;
72
73 pdu->size += len;
74 return size - len;
75 }
76
77 /* b - int8_t
78 * w - int16_t
79 * d - int32_t
80 * q - int64_t
81 * s - string
82 * u - numeric uid
83 * g - numeric gid
84 * S - stat
85 * Q - qid
86 * D - data blob (int32_t size followed by void *, results are not freed)
87 * T - array of strings (int16_t count, followed by strings)
88 * R - array of qids (int16_t count, followed by qids)
89 * A - stat for 9p2000.L (p9_stat_dotl)
90 * ? - if optional = 1, continue parsing
91 */
92
93 static int
p9pdu_vreadf(struct p9_fcall * pdu,int proto_version,const char * fmt,va_list ap)94 p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
95 va_list ap)
96 {
97 const char *ptr;
98 int errcode = 0;
99
100 for (ptr = fmt; *ptr; ptr++) {
101 switch (*ptr) {
102 case 'b':{
103 int8_t *val = va_arg(ap, int8_t *);
104 if (pdu_read(pdu, val, sizeof(*val))) {
105 errcode = -EFAULT;
106 break;
107 }
108 }
109 break;
110 case 'w':{
111 int16_t *val = va_arg(ap, int16_t *);
112 __le16 le_val;
113 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
114 errcode = -EFAULT;
115 break;
116 }
117 *val = le16_to_cpu(le_val);
118 }
119 break;
120 case 'd':{
121 int32_t *val = va_arg(ap, int32_t *);
122 __le32 le_val;
123 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
124 errcode = -EFAULT;
125 break;
126 }
127 *val = le32_to_cpu(le_val);
128 }
129 break;
130 case 'q':{
131 int64_t *val = va_arg(ap, int64_t *);
132 __le64 le_val;
133 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
134 errcode = -EFAULT;
135 break;
136 }
137 *val = le64_to_cpu(le_val);
138 }
139 break;
140 case 's':{
141 char **sptr = va_arg(ap, char **);
142 uint16_t len;
143
144 errcode = p9pdu_readf(pdu, proto_version,
145 "w", &len);
146 if (errcode)
147 break;
148
149 *sptr = kmalloc(len + 1, GFP_NOFS);
150 if (*sptr == NULL) {
151 errcode = -ENOMEM;
152 break;
153 }
154 if (pdu_read(pdu, *sptr, len)) {
155 errcode = -EFAULT;
156 kfree(*sptr);
157 *sptr = NULL;
158 } else
159 (*sptr)[len] = 0;
160 }
161 break;
162 case 'u': {
163 kuid_t *uid = va_arg(ap, kuid_t *);
164 __le32 le_val;
165 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
166 errcode = -EFAULT;
167 break;
168 }
169 *uid = make_kuid(&init_user_ns,
170 le32_to_cpu(le_val));
171 } break;
172 case 'g': {
173 kgid_t *gid = va_arg(ap, kgid_t *);
174 __le32 le_val;
175 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
176 errcode = -EFAULT;
177 break;
178 }
179 *gid = make_kgid(&init_user_ns,
180 le32_to_cpu(le_val));
181 } break;
182 case 'Q':{
183 struct p9_qid *qid =
184 va_arg(ap, struct p9_qid *);
185
186 errcode = p9pdu_readf(pdu, proto_version, "bdq",
187 &qid->type, &qid->version,
188 &qid->path);
189 }
190 break;
191 case 'S':{
192 struct p9_wstat *stbuf =
193 va_arg(ap, struct p9_wstat *);
194
195 memset(stbuf, 0, sizeof(struct p9_wstat));
196 stbuf->n_uid = stbuf->n_muid = INVALID_UID;
197 stbuf->n_gid = INVALID_GID;
198
199 errcode =
200 p9pdu_readf(pdu, proto_version,
201 "wwdQdddqssss?sugu",
202 &stbuf->size, &stbuf->type,
203 &stbuf->dev, &stbuf->qid,
204 &stbuf->mode, &stbuf->atime,
205 &stbuf->mtime, &stbuf->length,
206 &stbuf->name, &stbuf->uid,
207 &stbuf->gid, &stbuf->muid,
208 &stbuf->extension,
209 &stbuf->n_uid, &stbuf->n_gid,
210 &stbuf->n_muid);
211 if (errcode)
212 p9stat_free(stbuf);
213 }
214 break;
215 case 'D':{
216 uint32_t *count = va_arg(ap, uint32_t *);
217 void **data = va_arg(ap, void **);
218
219 errcode =
220 p9pdu_readf(pdu, proto_version, "d", count);
221 if (!errcode) {
222 *count =
223 min_t(uint32_t, *count,
224 pdu->size - pdu->offset);
225 *data = &pdu->sdata[pdu->offset];
226 }
227 }
228 break;
229 case 'T':{
230 uint16_t *nwname = va_arg(ap, uint16_t *);
231 char ***wnames = va_arg(ap, char ***);
232
233 *wnames = NULL;
234
235 errcode = p9pdu_readf(pdu, proto_version,
236 "w", nwname);
237 if (!errcode) {
238 *wnames =
239 kmalloc_array(*nwname,
240 sizeof(char *),
241 GFP_NOFS);
242 if (!*wnames)
243 errcode = -ENOMEM;
244 else
245 (*wnames)[0] = NULL;
246 }
247
248 if (!errcode) {
249 int i;
250
251 for (i = 0; i < *nwname; i++) {
252 errcode =
253 p9pdu_readf(pdu,
254 proto_version,
255 "s",
256 &(*wnames)[i]);
257 if (errcode) {
258 (*wnames)[i] = NULL;
259 break;
260 }
261 }
262 }
263
264 if (errcode) {
265 if (*wnames) {
266 int i;
267
268 for (i = 0; i < *nwname; i++) {
269 if (!(*wnames)[i])
270 break;
271 kfree((*wnames)[i]);
272 }
273 kfree(*wnames);
274 *wnames = NULL;
275 }
276 }
277 }
278 break;
279 case 'R':{
280 uint16_t *nwqid = va_arg(ap, uint16_t *);
281 struct p9_qid **wqids =
282 va_arg(ap, struct p9_qid **);
283
284 *wqids = NULL;
285
286 errcode =
287 p9pdu_readf(pdu, proto_version, "w", nwqid);
288 if (!errcode) {
289 *wqids =
290 kmalloc_array(*nwqid,
291 sizeof(struct p9_qid),
292 GFP_NOFS);
293 if (*wqids == NULL)
294 errcode = -ENOMEM;
295 }
296
297 if (!errcode) {
298 int i;
299
300 for (i = 0; i < *nwqid; i++) {
301 errcode =
302 p9pdu_readf(pdu,
303 proto_version,
304 "Q",
305 &(*wqids)[i]);
306 if (errcode)
307 break;
308 }
309 }
310
311 if (errcode) {
312 kfree(*wqids);
313 *wqids = NULL;
314 }
315 }
316 break;
317 case 'A': {
318 struct p9_stat_dotl *stbuf =
319 va_arg(ap, struct p9_stat_dotl *);
320
321 memset(stbuf, 0, sizeof(struct p9_stat_dotl));
322 errcode =
323 p9pdu_readf(pdu, proto_version,
324 "qQdugqqqqqqqqqqqqqqq",
325 &stbuf->st_result_mask,
326 &stbuf->qid,
327 &stbuf->st_mode,
328 &stbuf->st_uid, &stbuf->st_gid,
329 &stbuf->st_nlink,
330 &stbuf->st_rdev, &stbuf->st_size,
331 &stbuf->st_blksize, &stbuf->st_blocks,
332 &stbuf->st_atime_sec,
333 &stbuf->st_atime_nsec,
334 &stbuf->st_mtime_sec,
335 &stbuf->st_mtime_nsec,
336 &stbuf->st_ctime_sec,
337 &stbuf->st_ctime_nsec,
338 &stbuf->st_btime_sec,
339 &stbuf->st_btime_nsec,
340 &stbuf->st_gen,
341 &stbuf->st_data_version);
342 }
343 break;
344 case '?':
345 if ((proto_version != p9_proto_2000u) &&
346 (proto_version != p9_proto_2000L))
347 return 0;
348 break;
349 default:
350 BUG();
351 break;
352 }
353
354 if (errcode)
355 break;
356 }
357
358 return errcode;
359 }
360
361 int
p9pdu_vwritef(struct p9_fcall * pdu,int proto_version,const char * fmt,va_list ap)362 p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
363 va_list ap)
364 {
365 const char *ptr;
366 int errcode = 0;
367
368 for (ptr = fmt; *ptr; ptr++) {
369 switch (*ptr) {
370 case 'b':{
371 int8_t val = va_arg(ap, int);
372 if (pdu_write(pdu, &val, sizeof(val)))
373 errcode = -EFAULT;
374 }
375 break;
376 case 'w':{
377 __le16 val = cpu_to_le16(va_arg(ap, int));
378 if (pdu_write(pdu, &val, sizeof(val)))
379 errcode = -EFAULT;
380 }
381 break;
382 case 'd':{
383 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
384 if (pdu_write(pdu, &val, sizeof(val)))
385 errcode = -EFAULT;
386 }
387 break;
388 case 'q':{
389 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
390 if (pdu_write(pdu, &val, sizeof(val)))
391 errcode = -EFAULT;
392 }
393 break;
394 case 's':{
395 const char *sptr = va_arg(ap, const char *);
396 uint16_t len = 0;
397 if (sptr)
398 len = min_t(size_t, strlen(sptr),
399 USHRT_MAX);
400
401 errcode = p9pdu_writef(pdu, proto_version,
402 "w", len);
403 if (!errcode && pdu_write(pdu, sptr, len))
404 errcode = -EFAULT;
405 }
406 break;
407 case 'u': {
408 kuid_t uid = va_arg(ap, kuid_t);
409 __le32 val = cpu_to_le32(
410 from_kuid(&init_user_ns, uid));
411 if (pdu_write(pdu, &val, sizeof(val)))
412 errcode = -EFAULT;
413 } break;
414 case 'g': {
415 kgid_t gid = va_arg(ap, kgid_t);
416 __le32 val = cpu_to_le32(
417 from_kgid(&init_user_ns, gid));
418 if (pdu_write(pdu, &val, sizeof(val)))
419 errcode = -EFAULT;
420 } break;
421 case 'Q':{
422 const struct p9_qid *qid =
423 va_arg(ap, const struct p9_qid *);
424 errcode =
425 p9pdu_writef(pdu, proto_version, "bdq",
426 qid->type, qid->version,
427 qid->path);
428 } break;
429 case 'S':{
430 const struct p9_wstat *stbuf =
431 va_arg(ap, const struct p9_wstat *);
432 errcode =
433 p9pdu_writef(pdu, proto_version,
434 "wwdQdddqssss?sugu",
435 stbuf->size, stbuf->type,
436 stbuf->dev, &stbuf->qid,
437 stbuf->mode, stbuf->atime,
438 stbuf->mtime, stbuf->length,
439 stbuf->name, stbuf->uid,
440 stbuf->gid, stbuf->muid,
441 stbuf->extension, stbuf->n_uid,
442 stbuf->n_gid, stbuf->n_muid);
443 } break;
444 case 'V':{
445 uint32_t count = va_arg(ap, uint32_t);
446 struct iov_iter *from =
447 va_arg(ap, struct iov_iter *);
448 errcode = p9pdu_writef(pdu, proto_version, "d",
449 count);
450 if (!errcode && pdu_write_u(pdu, from, count))
451 errcode = -EFAULT;
452 }
453 break;
454 case 'T':{
455 uint16_t nwname = va_arg(ap, int);
456 const char **wnames = va_arg(ap, const char **);
457
458 errcode = p9pdu_writef(pdu, proto_version, "w",
459 nwname);
460 if (!errcode) {
461 int i;
462
463 for (i = 0; i < nwname; i++) {
464 errcode =
465 p9pdu_writef(pdu,
466 proto_version,
467 "s",
468 wnames[i]);
469 if (errcode)
470 break;
471 }
472 }
473 }
474 break;
475 case 'R':{
476 uint16_t nwqid = va_arg(ap, int);
477 struct p9_qid *wqids =
478 va_arg(ap, struct p9_qid *);
479
480 errcode = p9pdu_writef(pdu, proto_version, "w",
481 nwqid);
482 if (!errcode) {
483 int i;
484
485 for (i = 0; i < nwqid; i++) {
486 errcode =
487 p9pdu_writef(pdu,
488 proto_version,
489 "Q",
490 &wqids[i]);
491 if (errcode)
492 break;
493 }
494 }
495 }
496 break;
497 case 'I':{
498 struct p9_iattr_dotl *p9attr = va_arg(ap,
499 struct p9_iattr_dotl *);
500
501 errcode = p9pdu_writef(pdu, proto_version,
502 "ddugqqqqq",
503 p9attr->valid,
504 p9attr->mode,
505 p9attr->uid,
506 p9attr->gid,
507 p9attr->size,
508 p9attr->atime_sec,
509 p9attr->atime_nsec,
510 p9attr->mtime_sec,
511 p9attr->mtime_nsec);
512 }
513 break;
514 case '?':
515 if ((proto_version != p9_proto_2000u) &&
516 (proto_version != p9_proto_2000L))
517 return 0;
518 break;
519 default:
520 BUG();
521 break;
522 }
523
524 if (errcode)
525 break;
526 }
527
528 return errcode;
529 }
530
p9pdu_readf(struct p9_fcall * pdu,int proto_version,const char * fmt,...)531 int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
532 {
533 va_list ap;
534 int ret;
535
536 va_start(ap, fmt);
537 ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
538 va_end(ap);
539
540 return ret;
541 }
542
543 static int
p9pdu_writef(struct p9_fcall * pdu,int proto_version,const char * fmt,...)544 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
545 {
546 va_list ap;
547 int ret;
548
549 va_start(ap, fmt);
550 ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
551 va_end(ap);
552
553 return ret;
554 }
555
p9stat_read(struct p9_client * clnt,char * buf,int len,struct p9_wstat * st)556 int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)
557 {
558 struct p9_fcall fake_pdu;
559 int ret;
560
561 fake_pdu.size = len;
562 fake_pdu.capacity = len;
563 fake_pdu.sdata = buf;
564 fake_pdu.offset = 0;
565
566 ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st);
567 if (ret) {
568 p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
569 trace_9p_protocol_dump(clnt, &fake_pdu);
570 return ret;
571 }
572
573 return fake_pdu.offset;
574 }
575 EXPORT_SYMBOL(p9stat_read);
576
p9pdu_prepare(struct p9_fcall * pdu,int16_t tag,int8_t type)577 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
578 {
579 pdu->id = type;
580 return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
581 }
582
p9pdu_finalize(struct p9_client * clnt,struct p9_fcall * pdu)583 int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu)
584 {
585 int size = pdu->size;
586 int err;
587
588 pdu->size = 0;
589 err = p9pdu_writef(pdu, 0, "d", size);
590 pdu->size = size;
591
592 trace_9p_protocol_dump(clnt, pdu);
593 p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n",
594 pdu->size, pdu->id, pdu->tag);
595
596 return err;
597 }
598
p9pdu_reset(struct p9_fcall * pdu)599 void p9pdu_reset(struct p9_fcall *pdu)
600 {
601 pdu->offset = 0;
602 pdu->size = 0;
603 }
604
p9dirent_read(struct p9_client * clnt,char * buf,int len,struct p9_dirent * dirent)605 int p9dirent_read(struct p9_client *clnt, char *buf, int len,
606 struct p9_dirent *dirent)
607 {
608 struct p9_fcall fake_pdu;
609 int ret;
610 char *nameptr;
611
612 fake_pdu.size = len;
613 fake_pdu.capacity = len;
614 fake_pdu.sdata = buf;
615 fake_pdu.offset = 0;
616
617 ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid,
618 &dirent->d_off, &dirent->d_type, &nameptr);
619 if (ret) {
620 p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
621 trace_9p_protocol_dump(clnt, &fake_pdu);
622 return ret;
623 }
624
625 ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name));
626 if (ret < 0) {
627 p9_debug(P9_DEBUG_ERROR,
628 "On the wire dirent name too long: %s\n",
629 nameptr);
630 kfree(nameptr);
631 return ret;
632 }
633 kfree(nameptr);
634
635 return fake_pdu.offset;
636 }
637 EXPORT_SYMBOL(p9dirent_read);
638