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