Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * 9P Protocol Support Code
0004  *
0005  *  Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
0006  *
0007  *  Base on code from Anthony Liguori <aliguori@us.ibm.com>
0008  *  Copyright (C) 2008 by IBM, Corp.
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/errno.h>
0013 #include <linux/kernel.h>
0014 #include <linux/uaccess.h>
0015 #include <linux/slab.h>
0016 #include <linux/sched.h>
0017 #include <linux/stddef.h>
0018 #include <linux/types.h>
0019 #include <linux/uio.h>
0020 #include <net/9p/9p.h>
0021 #include <net/9p/client.h>
0022 #include "protocol.h"
0023 
0024 #include <trace/events/9p.h>
0025 
0026 static int
0027 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
0028 
0029 void p9stat_free(struct p9_wstat *stbuf)
0030 {
0031     kfree(stbuf->name);
0032     stbuf->name = NULL;
0033     kfree(stbuf->uid);
0034     stbuf->uid = NULL;
0035     kfree(stbuf->gid);
0036     stbuf->gid = NULL;
0037     kfree(stbuf->muid);
0038     stbuf->muid = NULL;
0039     kfree(stbuf->extension);
0040     stbuf->extension = NULL;
0041 }
0042 EXPORT_SYMBOL(p9stat_free);
0043 
0044 size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
0045 {
0046     size_t len = min(pdu->size - pdu->offset, size);
0047 
0048     memcpy(data, &pdu->sdata[pdu->offset], len);
0049     pdu->offset += len;
0050     return size - len;
0051 }
0052 
0053 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
0054 {
0055     size_t len = min(pdu->capacity - pdu->size, size);
0056 
0057     memcpy(&pdu->sdata[pdu->size], data, len);
0058     pdu->size += len;
0059     return size - len;
0060 }
0061 
0062 static size_t
0063 pdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size)
0064 {
0065     size_t len = min(pdu->capacity - pdu->size, size);
0066 
0067     if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, from))
0068         len = 0;
0069 
0070     pdu->size += len;
0071     return size - len;
0072 }
0073 
0074 /*  b - int8_t
0075  *  w - int16_t
0076  *  d - int32_t
0077  *  q - int64_t
0078  *  s - string
0079  *  u - numeric uid
0080  *  g - numeric gid
0081  *  S - stat
0082  *  Q - qid
0083  *  D - data blob (int32_t size followed by void *, results are not freed)
0084  *  T - array of strings (int16_t count, followed by strings)
0085  *  R - array of qids (int16_t count, followed by qids)
0086  *  A - stat for 9p2000.L (p9_stat_dotl)
0087  *  ? - if optional = 1, continue parsing
0088  */
0089 
0090 static int
0091 p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
0092          va_list ap)
0093 {
0094     const char *ptr;
0095     int errcode = 0;
0096 
0097     for (ptr = fmt; *ptr; ptr++) {
0098         switch (*ptr) {
0099         case 'b':{
0100                 int8_t *val = va_arg(ap, int8_t *);
0101                 if (pdu_read(pdu, val, sizeof(*val))) {
0102                     errcode = -EFAULT;
0103                     break;
0104                 }
0105             }
0106             break;
0107         case 'w':{
0108                 int16_t *val = va_arg(ap, int16_t *);
0109                 __le16 le_val;
0110                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
0111                     errcode = -EFAULT;
0112                     break;
0113                 }
0114                 *val = le16_to_cpu(le_val);
0115             }
0116             break;
0117         case 'd':{
0118                 int32_t *val = va_arg(ap, int32_t *);
0119                 __le32 le_val;
0120                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
0121                     errcode = -EFAULT;
0122                     break;
0123                 }
0124                 *val = le32_to_cpu(le_val);
0125             }
0126             break;
0127         case 'q':{
0128                 int64_t *val = va_arg(ap, int64_t *);
0129                 __le64 le_val;
0130                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
0131                     errcode = -EFAULT;
0132                     break;
0133                 }
0134                 *val = le64_to_cpu(le_val);
0135             }
0136             break;
0137         case 's':{
0138                 char **sptr = va_arg(ap, char **);
0139                 uint16_t len;
0140 
0141                 errcode = p9pdu_readf(pdu, proto_version,
0142                                 "w", &len);
0143                 if (errcode)
0144                     break;
0145 
0146                 *sptr = kmalloc(len + 1, GFP_NOFS);
0147                 if (*sptr == NULL) {
0148                     errcode = -ENOMEM;
0149                     break;
0150                 }
0151                 if (pdu_read(pdu, *sptr, len)) {
0152                     errcode = -EFAULT;
0153                     kfree(*sptr);
0154                     *sptr = NULL;
0155                 } else
0156                     (*sptr)[len] = 0;
0157             }
0158             break;
0159         case 'u': {
0160                 kuid_t *uid = va_arg(ap, kuid_t *);
0161                 __le32 le_val;
0162                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
0163                     errcode = -EFAULT;
0164                     break;
0165                 }
0166                 *uid = make_kuid(&init_user_ns,
0167                          le32_to_cpu(le_val));
0168             } break;
0169         case 'g': {
0170                 kgid_t *gid = va_arg(ap, kgid_t *);
0171                 __le32 le_val;
0172                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
0173                     errcode = -EFAULT;
0174                     break;
0175                 }
0176                 *gid = make_kgid(&init_user_ns,
0177                          le32_to_cpu(le_val));
0178             } break;
0179         case 'Q':{
0180                 struct p9_qid *qid =
0181                     va_arg(ap, struct p9_qid *);
0182 
0183                 errcode = p9pdu_readf(pdu, proto_version, "bdq",
0184                               &qid->type, &qid->version,
0185                               &qid->path);
0186             }
0187             break;
0188         case 'S':{
0189                 struct p9_wstat *stbuf =
0190                     va_arg(ap, struct p9_wstat *);
0191 
0192                 memset(stbuf, 0, sizeof(struct p9_wstat));
0193                 stbuf->n_uid = stbuf->n_muid = INVALID_UID;
0194                 stbuf->n_gid = INVALID_GID;
0195 
0196                 errcode =
0197                     p9pdu_readf(pdu, proto_version,
0198                         "wwdQdddqssss?sugu",
0199                         &stbuf->size, &stbuf->type,
0200                         &stbuf->dev, &stbuf->qid,
0201                         &stbuf->mode, &stbuf->atime,
0202                         &stbuf->mtime, &stbuf->length,
0203                         &stbuf->name, &stbuf->uid,
0204                         &stbuf->gid, &stbuf->muid,
0205                         &stbuf->extension,
0206                         &stbuf->n_uid, &stbuf->n_gid,
0207                         &stbuf->n_muid);
0208                 if (errcode)
0209                     p9stat_free(stbuf);
0210             }
0211             break;
0212         case 'D':{
0213                 uint32_t *count = va_arg(ap, uint32_t *);
0214                 void **data = va_arg(ap, void **);
0215 
0216                 errcode =
0217                     p9pdu_readf(pdu, proto_version, "d", count);
0218                 if (!errcode) {
0219                     *count =
0220                         min_t(uint32_t, *count,
0221                           pdu->size - pdu->offset);
0222                     *data = &pdu->sdata[pdu->offset];
0223                 }
0224             }
0225             break;
0226         case 'T':{
0227                 uint16_t *nwname = va_arg(ap, uint16_t *);
0228                 char ***wnames = va_arg(ap, char ***);
0229 
0230                 errcode = p9pdu_readf(pdu, proto_version,
0231                                 "w", nwname);
0232                 if (!errcode) {
0233                     *wnames =
0234                         kmalloc_array(*nwname,
0235                               sizeof(char *),
0236                               GFP_NOFS);
0237                     if (!*wnames)
0238                         errcode = -ENOMEM;
0239                 }
0240 
0241                 if (!errcode) {
0242                     int i;
0243 
0244                     for (i = 0; i < *nwname; i++) {
0245                         errcode =
0246                             p9pdu_readf(pdu,
0247                                 proto_version,
0248                                 "s",
0249                                 &(*wnames)[i]);
0250                         if (errcode)
0251                             break;
0252                     }
0253                 }
0254 
0255                 if (errcode) {
0256                     if (*wnames) {
0257                         int i;
0258 
0259                         for (i = 0; i < *nwname; i++)
0260                             kfree((*wnames)[i]);
0261                     }
0262                     kfree(*wnames);
0263                     *wnames = NULL;
0264                 }
0265             }
0266             break;
0267         case 'R':{
0268                 uint16_t *nwqid = va_arg(ap, uint16_t *);
0269                 struct p9_qid **wqids =
0270                     va_arg(ap, struct p9_qid **);
0271 
0272                 *wqids = NULL;
0273 
0274                 errcode =
0275                     p9pdu_readf(pdu, proto_version, "w", nwqid);
0276                 if (!errcode) {
0277                     *wqids =
0278                         kmalloc_array(*nwqid,
0279                               sizeof(struct p9_qid),
0280                               GFP_NOFS);
0281                     if (*wqids == NULL)
0282                         errcode = -ENOMEM;
0283                 }
0284 
0285                 if (!errcode) {
0286                     int i;
0287 
0288                     for (i = 0; i < *nwqid; i++) {
0289                         errcode =
0290                             p9pdu_readf(pdu,
0291                                 proto_version,
0292                                 "Q",
0293                                 &(*wqids)[i]);
0294                         if (errcode)
0295                             break;
0296                     }
0297                 }
0298 
0299                 if (errcode) {
0300                     kfree(*wqids);
0301                     *wqids = NULL;
0302                 }
0303             }
0304             break;
0305         case 'A': {
0306                 struct p9_stat_dotl *stbuf =
0307                     va_arg(ap, struct p9_stat_dotl *);
0308 
0309                 memset(stbuf, 0, sizeof(struct p9_stat_dotl));
0310                 errcode =
0311                     p9pdu_readf(pdu, proto_version,
0312                     "qQdugqqqqqqqqqqqqqqq",
0313                     &stbuf->st_result_mask,
0314                     &stbuf->qid,
0315                     &stbuf->st_mode,
0316                     &stbuf->st_uid, &stbuf->st_gid,
0317                     &stbuf->st_nlink,
0318                     &stbuf->st_rdev, &stbuf->st_size,
0319                     &stbuf->st_blksize, &stbuf->st_blocks,
0320                     &stbuf->st_atime_sec,
0321                     &stbuf->st_atime_nsec,
0322                     &stbuf->st_mtime_sec,
0323                     &stbuf->st_mtime_nsec,
0324                     &stbuf->st_ctime_sec,
0325                     &stbuf->st_ctime_nsec,
0326                     &stbuf->st_btime_sec,
0327                     &stbuf->st_btime_nsec,
0328                     &stbuf->st_gen,
0329                     &stbuf->st_data_version);
0330             }
0331             break;
0332         case '?':
0333             if ((proto_version != p9_proto_2000u) &&
0334                 (proto_version != p9_proto_2000L))
0335                 return 0;
0336             break;
0337         default:
0338             BUG();
0339             break;
0340         }
0341 
0342         if (errcode)
0343             break;
0344     }
0345 
0346     return errcode;
0347 }
0348 
0349 int
0350 p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
0351     va_list ap)
0352 {
0353     const char *ptr;
0354     int errcode = 0;
0355 
0356     for (ptr = fmt; *ptr; ptr++) {
0357         switch (*ptr) {
0358         case 'b':{
0359                 int8_t val = va_arg(ap, int);
0360                 if (pdu_write(pdu, &val, sizeof(val)))
0361                     errcode = -EFAULT;
0362             }
0363             break;
0364         case 'w':{
0365                 __le16 val = cpu_to_le16(va_arg(ap, int));
0366                 if (pdu_write(pdu, &val, sizeof(val)))
0367                     errcode = -EFAULT;
0368             }
0369             break;
0370         case 'd':{
0371                 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
0372                 if (pdu_write(pdu, &val, sizeof(val)))
0373                     errcode = -EFAULT;
0374             }
0375             break;
0376         case 'q':{
0377                 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
0378                 if (pdu_write(pdu, &val, sizeof(val)))
0379                     errcode = -EFAULT;
0380             }
0381             break;
0382         case 's':{
0383                 const char *sptr = va_arg(ap, const char *);
0384                 uint16_t len = 0;
0385                 if (sptr)
0386                     len = min_t(size_t, strlen(sptr),
0387                                 USHRT_MAX);
0388 
0389                 errcode = p9pdu_writef(pdu, proto_version,
0390                                 "w", len);
0391                 if (!errcode && pdu_write(pdu, sptr, len))
0392                     errcode = -EFAULT;
0393             }
0394             break;
0395         case 'u': {
0396                 kuid_t uid = va_arg(ap, kuid_t);
0397                 __le32 val = cpu_to_le32(
0398                         from_kuid(&init_user_ns, uid));
0399                 if (pdu_write(pdu, &val, sizeof(val)))
0400                     errcode = -EFAULT;
0401             } break;
0402         case 'g': {
0403                 kgid_t gid = va_arg(ap, kgid_t);
0404                 __le32 val = cpu_to_le32(
0405                         from_kgid(&init_user_ns, gid));
0406                 if (pdu_write(pdu, &val, sizeof(val)))
0407                     errcode = -EFAULT;
0408             } break;
0409         case 'Q':{
0410                 const struct p9_qid *qid =
0411                     va_arg(ap, const struct p9_qid *);
0412                 errcode =
0413                     p9pdu_writef(pdu, proto_version, "bdq",
0414                          qid->type, qid->version,
0415                          qid->path);
0416             } break;
0417         case 'S':{
0418                 const struct p9_wstat *stbuf =
0419                     va_arg(ap, const struct p9_wstat *);
0420                 errcode =
0421                     p9pdu_writef(pdu, proto_version,
0422                          "wwdQdddqssss?sugu",
0423                          stbuf->size, stbuf->type,
0424                          stbuf->dev, &stbuf->qid,
0425                          stbuf->mode, stbuf->atime,
0426                          stbuf->mtime, stbuf->length,
0427                          stbuf->name, stbuf->uid,
0428                          stbuf->gid, stbuf->muid,
0429                          stbuf->extension, stbuf->n_uid,
0430                          stbuf->n_gid, stbuf->n_muid);
0431             } break;
0432         case 'V':{
0433                 uint32_t count = va_arg(ap, uint32_t);
0434                 struct iov_iter *from =
0435                         va_arg(ap, struct iov_iter *);
0436                 errcode = p9pdu_writef(pdu, proto_version, "d",
0437                                     count);
0438                 if (!errcode && pdu_write_u(pdu, from, count))
0439                     errcode = -EFAULT;
0440             }
0441             break;
0442         case 'T':{
0443                 uint16_t nwname = va_arg(ap, int);
0444                 const char **wnames = va_arg(ap, const char **);
0445 
0446                 errcode = p9pdu_writef(pdu, proto_version, "w",
0447                                     nwname);
0448                 if (!errcode) {
0449                     int i;
0450 
0451                     for (i = 0; i < nwname; i++) {
0452                         errcode =
0453                             p9pdu_writef(pdu,
0454                                 proto_version,
0455                                  "s",
0456                                  wnames[i]);
0457                         if (errcode)
0458                             break;
0459                     }
0460                 }
0461             }
0462             break;
0463         case 'R':{
0464                 uint16_t nwqid = va_arg(ap, int);
0465                 struct p9_qid *wqids =
0466                     va_arg(ap, struct p9_qid *);
0467 
0468                 errcode = p9pdu_writef(pdu, proto_version, "w",
0469                                     nwqid);
0470                 if (!errcode) {
0471                     int i;
0472 
0473                     for (i = 0; i < nwqid; i++) {
0474                         errcode =
0475                             p9pdu_writef(pdu,
0476                                 proto_version,
0477                                  "Q",
0478                                  &wqids[i]);
0479                         if (errcode)
0480                             break;
0481                     }
0482                 }
0483             }
0484             break;
0485         case 'I':{
0486                 struct p9_iattr_dotl *p9attr = va_arg(ap,
0487                             struct p9_iattr_dotl *);
0488 
0489                 errcode = p9pdu_writef(pdu, proto_version,
0490                             "ddugqqqqq",
0491                             p9attr->valid,
0492                             p9attr->mode,
0493                             p9attr->uid,
0494                             p9attr->gid,
0495                             p9attr->size,
0496                             p9attr->atime_sec,
0497                             p9attr->atime_nsec,
0498                             p9attr->mtime_sec,
0499                             p9attr->mtime_nsec);
0500             }
0501             break;
0502         case '?':
0503             if ((proto_version != p9_proto_2000u) &&
0504                 (proto_version != p9_proto_2000L))
0505                 return 0;
0506             break;
0507         default:
0508             BUG();
0509             break;
0510         }
0511 
0512         if (errcode)
0513             break;
0514     }
0515 
0516     return errcode;
0517 }
0518 
0519 int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
0520 {
0521     va_list ap;
0522     int ret;
0523 
0524     va_start(ap, fmt);
0525     ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
0526     va_end(ap);
0527 
0528     return ret;
0529 }
0530 
0531 static int
0532 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
0533 {
0534     va_list ap;
0535     int ret;
0536 
0537     va_start(ap, fmt);
0538     ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
0539     va_end(ap);
0540 
0541     return ret;
0542 }
0543 
0544 int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)
0545 {
0546     struct p9_fcall fake_pdu;
0547     int ret;
0548 
0549     fake_pdu.size = len;
0550     fake_pdu.capacity = len;
0551     fake_pdu.sdata = buf;
0552     fake_pdu.offset = 0;
0553 
0554     ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st);
0555     if (ret) {
0556         p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
0557         trace_9p_protocol_dump(clnt, &fake_pdu);
0558         return ret;
0559     }
0560 
0561     return fake_pdu.offset;
0562 }
0563 EXPORT_SYMBOL(p9stat_read);
0564 
0565 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
0566 {
0567     pdu->id = type;
0568     return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
0569 }
0570 
0571 int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu)
0572 {
0573     int size = pdu->size;
0574     int err;
0575 
0576     pdu->size = 0;
0577     err = p9pdu_writef(pdu, 0, "d", size);
0578     pdu->size = size;
0579 
0580     trace_9p_protocol_dump(clnt, pdu);
0581     p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n",
0582          pdu->size, pdu->id, pdu->tag);
0583 
0584     return err;
0585 }
0586 
0587 void p9pdu_reset(struct p9_fcall *pdu)
0588 {
0589     pdu->offset = 0;
0590     pdu->size = 0;
0591 }
0592 
0593 int p9dirent_read(struct p9_client *clnt, char *buf, int len,
0594           struct p9_dirent *dirent)
0595 {
0596     struct p9_fcall fake_pdu;
0597     int ret;
0598     char *nameptr;
0599 
0600     fake_pdu.size = len;
0601     fake_pdu.capacity = len;
0602     fake_pdu.sdata = buf;
0603     fake_pdu.offset = 0;
0604 
0605     ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid,
0606               &dirent->d_off, &dirent->d_type, &nameptr);
0607     if (ret) {
0608         p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
0609         trace_9p_protocol_dump(clnt, &fake_pdu);
0610         return ret;
0611     }
0612 
0613     ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name));
0614     if (ret < 0) {
0615         p9_debug(P9_DEBUG_ERROR,
0616              "On the wire dirent name too long: %s\n",
0617              nameptr);
0618         kfree(nameptr);
0619         return ret;
0620     }
0621     kfree(nameptr);
0622 
0623     return fake_pdu.offset;
0624 }
0625 EXPORT_SYMBOL(p9dirent_read);