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