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