• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
p9stat_free(struct p9_wstat * stbuf)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 
pdu_read(struct p9_fcall * pdu,void * data,size_t size)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 
pdu_write(struct p9_fcall * pdu,const void * data,size_t size)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
pdu_write_u(struct p9_fcall * pdu,struct iov_iter * from,size_t size)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(&pdu->sdata[pdu->size], len, &i) != len)
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
p9pdu_vreadf(struct p9_fcall * pdu,int proto_version,const char * fmt,va_list ap)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 = -EFAULT;
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(sizeof(char *) * *nwname,
251 						    GFP_NOFS);
252 					if (!*wnames)
253 						errcode = -ENOMEM;
254 				}
255 
256 				if (!errcode) {
257 					int i;
258 
259 					for (i = 0; i < *nwname; i++) {
260 						errcode =
261 						    p9pdu_readf(pdu,
262 								proto_version,
263 								"s",
264 								&(*wnames)[i]);
265 						if (errcode)
266 							break;
267 					}
268 				}
269 
270 				if (errcode) {
271 					if (*wnames) {
272 						int i;
273 
274 						for (i = 0; i < *nwname; i++)
275 							kfree((*wnames)[i]);
276 					}
277 					kfree(*wnames);
278 					*wnames = NULL;
279 				}
280 			}
281 			break;
282 		case 'R':{
283 				uint16_t *nwqid = va_arg(ap, uint16_t *);
284 				struct p9_qid **wqids =
285 				    va_arg(ap, struct p9_qid **);
286 
287 				*wqids = NULL;
288 
289 				errcode =
290 				    p9pdu_readf(pdu, proto_version, "w", nwqid);
291 				if (!errcode) {
292 					*wqids =
293 					    kmalloc(*nwqid *
294 						    sizeof(struct p9_qid),
295 						    GFP_NOFS);
296 					if (*wqids == NULL)
297 						errcode = -ENOMEM;
298 				}
299 
300 				if (!errcode) {
301 					int i;
302 
303 					for (i = 0; i < *nwqid; i++) {
304 						errcode =
305 						    p9pdu_readf(pdu,
306 								proto_version,
307 								"Q",
308 								&(*wqids)[i]);
309 						if (errcode)
310 							break;
311 					}
312 				}
313 
314 				if (errcode) {
315 					kfree(*wqids);
316 					*wqids = NULL;
317 				}
318 			}
319 			break;
320 		case 'A': {
321 				struct p9_stat_dotl *stbuf =
322 				    va_arg(ap, struct p9_stat_dotl *);
323 
324 				memset(stbuf, 0, sizeof(struct p9_stat_dotl));
325 				errcode =
326 				    p9pdu_readf(pdu, proto_version,
327 					"qQdugqqqqqqqqqqqqqqq",
328 					&stbuf->st_result_mask,
329 					&stbuf->qid,
330 					&stbuf->st_mode,
331 					&stbuf->st_uid, &stbuf->st_gid,
332 					&stbuf->st_nlink,
333 					&stbuf->st_rdev, &stbuf->st_size,
334 					&stbuf->st_blksize, &stbuf->st_blocks,
335 					&stbuf->st_atime_sec,
336 					&stbuf->st_atime_nsec,
337 					&stbuf->st_mtime_sec,
338 					&stbuf->st_mtime_nsec,
339 					&stbuf->st_ctime_sec,
340 					&stbuf->st_ctime_nsec,
341 					&stbuf->st_btime_sec,
342 					&stbuf->st_btime_nsec,
343 					&stbuf->st_gen,
344 					&stbuf->st_data_version);
345 			}
346 			break;
347 		case '?':
348 			if ((proto_version != p9_proto_2000u) &&
349 				(proto_version != p9_proto_2000L))
350 				return 0;
351 			break;
352 		default:
353 			BUG();
354 			break;
355 		}
356 
357 		if (errcode)
358 			break;
359 	}
360 
361 	return errcode;
362 }
363 
364 int
p9pdu_vwritef(struct p9_fcall * pdu,int proto_version,const char * fmt,va_list ap)365 p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
366 	va_list ap)
367 {
368 	const char *ptr;
369 	int errcode = 0;
370 
371 	for (ptr = fmt; *ptr; ptr++) {
372 		switch (*ptr) {
373 		case 'b':{
374 				int8_t val = va_arg(ap, int);
375 				if (pdu_write(pdu, &val, sizeof(val)))
376 					errcode = -EFAULT;
377 			}
378 			break;
379 		case 'w':{
380 				__le16 val = cpu_to_le16(va_arg(ap, int));
381 				if (pdu_write(pdu, &val, sizeof(val)))
382 					errcode = -EFAULT;
383 			}
384 			break;
385 		case 'd':{
386 				__le32 val = cpu_to_le32(va_arg(ap, int32_t));
387 				if (pdu_write(pdu, &val, sizeof(val)))
388 					errcode = -EFAULT;
389 			}
390 			break;
391 		case 'q':{
392 				__le64 val = cpu_to_le64(va_arg(ap, int64_t));
393 				if (pdu_write(pdu, &val, sizeof(val)))
394 					errcode = -EFAULT;
395 			}
396 			break;
397 		case 's':{
398 				const char *sptr = va_arg(ap, const char *);
399 				uint16_t len = 0;
400 				if (sptr)
401 					len = min_t(size_t, strlen(sptr),
402 								USHRT_MAX);
403 
404 				errcode = p9pdu_writef(pdu, proto_version,
405 								"w", len);
406 				if (!errcode && pdu_write(pdu, sptr, len))
407 					errcode = -EFAULT;
408 			}
409 			break;
410 		case 'u': {
411 				kuid_t uid = va_arg(ap, kuid_t);
412 				__le32 val = cpu_to_le32(
413 						from_kuid(&init_user_ns, uid));
414 				if (pdu_write(pdu, &val, sizeof(val)))
415 					errcode = -EFAULT;
416 			} break;
417 		case 'g': {
418 				kgid_t gid = va_arg(ap, kgid_t);
419 				__le32 val = cpu_to_le32(
420 						from_kgid(&init_user_ns, gid));
421 				if (pdu_write(pdu, &val, sizeof(val)))
422 					errcode = -EFAULT;
423 			} break;
424 		case 'Q':{
425 				const struct p9_qid *qid =
426 				    va_arg(ap, const struct p9_qid *);
427 				errcode =
428 				    p9pdu_writef(pdu, proto_version, "bdq",
429 						 qid->type, qid->version,
430 						 qid->path);
431 			} break;
432 		case 'S':{
433 				const struct p9_wstat *stbuf =
434 				    va_arg(ap, const struct p9_wstat *);
435 				errcode =
436 				    p9pdu_writef(pdu, proto_version,
437 						 "wwdQdddqssss?sugu",
438 						 stbuf->size, stbuf->type,
439 						 stbuf->dev, &stbuf->qid,
440 						 stbuf->mode, stbuf->atime,
441 						 stbuf->mtime, stbuf->length,
442 						 stbuf->name, stbuf->uid,
443 						 stbuf->gid, stbuf->muid,
444 						 stbuf->extension, stbuf->n_uid,
445 						 stbuf->n_gid, stbuf->n_muid);
446 			} break;
447 		case 'V':{
448 				uint32_t count = va_arg(ap, uint32_t);
449 				struct iov_iter *from =
450 						va_arg(ap, struct iov_iter *);
451 				errcode = p9pdu_writef(pdu, proto_version, "d",
452 									count);
453 				if (!errcode && pdu_write_u(pdu, from, count))
454 					errcode = -EFAULT;
455 			}
456 			break;
457 		case 'T':{
458 				uint16_t nwname = va_arg(ap, int);
459 				const char **wnames = va_arg(ap, const char **);
460 
461 				errcode = p9pdu_writef(pdu, proto_version, "w",
462 									nwname);
463 				if (!errcode) {
464 					int i;
465 
466 					for (i = 0; i < nwname; i++) {
467 						errcode =
468 						    p9pdu_writef(pdu,
469 								proto_version,
470 								 "s",
471 								 wnames[i]);
472 						if (errcode)
473 							break;
474 					}
475 				}
476 			}
477 			break;
478 		case 'R':{
479 				uint16_t nwqid = va_arg(ap, int);
480 				struct p9_qid *wqids =
481 				    va_arg(ap, struct p9_qid *);
482 
483 				errcode = p9pdu_writef(pdu, proto_version, "w",
484 									nwqid);
485 				if (!errcode) {
486 					int i;
487 
488 					for (i = 0; i < nwqid; i++) {
489 						errcode =
490 						    p9pdu_writef(pdu,
491 								proto_version,
492 								 "Q",
493 								 &wqids[i]);
494 						if (errcode)
495 							break;
496 					}
497 				}
498 			}
499 			break;
500 		case 'I':{
501 				struct p9_iattr_dotl *p9attr = va_arg(ap,
502 							struct p9_iattr_dotl *);
503 
504 				errcode = p9pdu_writef(pdu, proto_version,
505 							"ddugqqqqq",
506 							p9attr->valid,
507 							p9attr->mode,
508 							p9attr->uid,
509 							p9attr->gid,
510 							p9attr->size,
511 							p9attr->atime_sec,
512 							p9attr->atime_nsec,
513 							p9attr->mtime_sec,
514 							p9attr->mtime_nsec);
515 			}
516 			break;
517 		case '?':
518 			if ((proto_version != p9_proto_2000u) &&
519 				(proto_version != p9_proto_2000L))
520 				return 0;
521 			break;
522 		default:
523 			BUG();
524 			break;
525 		}
526 
527 		if (errcode)
528 			break;
529 	}
530 
531 	return errcode;
532 }
533 
p9pdu_readf(struct p9_fcall * pdu,int proto_version,const char * fmt,...)534 int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
535 {
536 	va_list ap;
537 	int ret;
538 
539 	va_start(ap, fmt);
540 	ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
541 	va_end(ap);
542 
543 	return ret;
544 }
545 
546 static int
p9pdu_writef(struct p9_fcall * pdu,int proto_version,const char * fmt,...)547 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
548 {
549 	va_list ap;
550 	int ret;
551 
552 	va_start(ap, fmt);
553 	ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
554 	va_end(ap);
555 
556 	return ret;
557 }
558 
p9stat_read(struct p9_client * clnt,char * buf,int len,struct p9_wstat * st)559 int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)
560 {
561 	struct p9_fcall fake_pdu;
562 	int ret;
563 
564 	fake_pdu.size = len;
565 	fake_pdu.capacity = len;
566 	fake_pdu.sdata = buf;
567 	fake_pdu.offset = 0;
568 
569 	ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st);
570 	if (ret) {
571 		p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
572 		trace_9p_protocol_dump(clnt, &fake_pdu);
573 		return ret;
574 	}
575 
576 	return fake_pdu.offset;
577 }
578 EXPORT_SYMBOL(p9stat_read);
579 
p9pdu_prepare(struct p9_fcall * pdu,int16_t tag,int8_t type)580 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
581 {
582 	pdu->id = type;
583 	return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
584 }
585 
p9pdu_finalize(struct p9_client * clnt,struct p9_fcall * pdu)586 int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu)
587 {
588 	int size = pdu->size;
589 	int err;
590 
591 	pdu->size = 0;
592 	err = p9pdu_writef(pdu, 0, "d", size);
593 	pdu->size = size;
594 
595 	trace_9p_protocol_dump(clnt, pdu);
596 	p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n",
597 		 pdu->size, pdu->id, pdu->tag);
598 
599 	return err;
600 }
601 
p9pdu_reset(struct p9_fcall * pdu)602 void p9pdu_reset(struct p9_fcall *pdu)
603 {
604 	pdu->offset = 0;
605 	pdu->size = 0;
606 }
607 
p9dirent_read(struct p9_client * clnt,char * buf,int len,struct p9_dirent * dirent)608 int p9dirent_read(struct p9_client *clnt, char *buf, int len,
609 		  struct p9_dirent *dirent)
610 {
611 	struct p9_fcall fake_pdu;
612 	int ret;
613 	char *nameptr;
614 
615 	fake_pdu.size = len;
616 	fake_pdu.capacity = len;
617 	fake_pdu.sdata = buf;
618 	fake_pdu.offset = 0;
619 
620 	ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid,
621 			  &dirent->d_off, &dirent->d_type, &nameptr);
622 	if (ret) {
623 		p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
624 		trace_9p_protocol_dump(clnt, &fake_pdu);
625 		return ret;
626 	}
627 
628 	ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name));
629 	if (ret < 0) {
630 		p9_debug(P9_DEBUG_ERROR,
631 			 "On the wire dirent name too long: %s\n",
632 			 nameptr);
633 		kfree(nameptr);
634 		return ret;
635 	}
636 	kfree(nameptr);
637 
638 	return fake_pdu.offset;
639 }
640 EXPORT_SYMBOL(p9dirent_read);
641