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