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