• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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