]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - net/9p/protocol.c
[PATCH] fs: add a sanity check in d_free
[linux-2.6-omap-h63xx.git] / net / 9p / protocol.c
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/uaccess.h>
31 #include <linux/sched.h>
32 #include <net/9p/9p.h>
33 #include <net/9p/client.h>
34 #include "protocol.h"
35
36 #ifndef MIN
37 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
38 #endif
39
40 #ifndef MAX
41 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
42 #endif
43
44 #ifndef offset_of
45 #define offset_of(type, memb) \
46         ((unsigned long)(&((type *)0)->memb))
47 #endif
48 #ifndef container_of
49 #define container_of(obj, type, memb) \
50         ((type *)(((char *)obj) - offset_of(type, memb)))
51 #endif
52
53 static int
54 p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...);
55
56 void
57 p9pdu_dump(int way, struct p9_fcall *pdu)
58 {
59         int i, n;
60         u8 *data = pdu->sdata;
61         int datalen = pdu->size;
62         char buf[255];
63         int buflen = 255;
64
65         i = n = 0;
66         if (datalen > (buflen-16))
67                 datalen = buflen-16;
68         while (i < datalen) {
69                 n += scnprintf(buf + n, buflen - n, "%02x ", data[i]);
70                 if (i%4 == 3)
71                         n += scnprintf(buf + n, buflen - n, " ");
72                 if (i%32 == 31)
73                         n += scnprintf(buf + n, buflen - n, "\n");
74
75                 i++;
76         }
77         n += scnprintf(buf + n, buflen - n, "\n");
78
79         if (way)
80                 P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf);
81         else
82                 P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf);
83 }
84 EXPORT_SYMBOL(p9pdu_dump);
85
86 void p9stat_free(struct p9_wstat *stbuf)
87 {
88         kfree(stbuf->name);
89         kfree(stbuf->uid);
90         kfree(stbuf->gid);
91         kfree(stbuf->muid);
92         kfree(stbuf->extension);
93 }
94 EXPORT_SYMBOL(p9stat_free);
95
96 static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
97 {
98         size_t len = MIN(pdu->size - pdu->offset, size);
99         memcpy(data, &pdu->sdata[pdu->offset], len);
100         pdu->offset += len;
101         return size - len;
102 }
103
104 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
105 {
106         size_t len = MIN(pdu->capacity - pdu->size, size);
107         memcpy(&pdu->sdata[pdu->size], data, len);
108         pdu->size += len;
109         return size - len;
110 }
111
112 static size_t
113 pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
114 {
115         size_t len = MIN(pdu->capacity - pdu->size, size);
116         int err = copy_from_user(&pdu->sdata[pdu->size], udata, len);
117         if (err)
118                 printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
119
120         pdu->size += len;
121         return size - len;
122 }
123
124 /*
125         b - int8_t
126         w - int16_t
127         d - int32_t
128         q - int64_t
129         s - string
130         S - stat
131         Q - qid
132         D - data blob (int32_t size followed by void *, results are not freed)
133         T - array of strings (int16_t count, followed by strings)
134         R - array of qids (int16_t count, followed by qids)
135         ? - if optional = 1, continue parsing
136 */
137
138 static int
139 p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
140 {
141         const char *ptr;
142         int errcode = 0;
143
144         for (ptr = fmt; *ptr; ptr++) {
145                 switch (*ptr) {
146                 case 'b':{
147                                 int8_t *val = va_arg(ap, int8_t *);
148                                 if (pdu_read(pdu, val, sizeof(*val))) {
149                                         errcode = -EFAULT;
150                                         break;
151                                 }
152                         }
153                         break;
154                 case 'w':{
155                                 int16_t *val = va_arg(ap, int16_t *);
156                                 if (pdu_read(pdu, val, sizeof(*val))) {
157                                         errcode = -EFAULT;
158                                         break;
159                                 }
160                                 *val = cpu_to_le16(*val);
161                         }
162                         break;
163                 case 'd':{
164                                 int32_t *val = va_arg(ap, int32_t *);
165                                 if (pdu_read(pdu, val, sizeof(*val))) {
166                                         errcode = -EFAULT;
167                                         break;
168                                 }
169                                 *val = cpu_to_le32(*val);
170                         }
171                         break;
172                 case 'q':{
173                                 int64_t *val = va_arg(ap, int64_t *);
174                                 if (pdu_read(pdu, val, sizeof(*val))) {
175                                         errcode = -EFAULT;
176                                         break;
177                                 }
178                                 *val = cpu_to_le64(*val);
179                         }
180                         break;
181                 case 's':{
182                                 char **ptr = va_arg(ap, char **);
183                                 int16_t len;
184                                 int size;
185
186                                 errcode = p9pdu_readf(pdu, optional, "w", &len);
187                                 if (errcode)
188                                         break;
189
190                                 size = MAX(len, 0);
191
192                                 *ptr = kmalloc(size + 1, GFP_KERNEL);
193                                 if (*ptr == NULL) {
194                                         errcode = -EFAULT;
195                                         break;
196                                 }
197                                 if (pdu_read(pdu, *ptr, size)) {
198                                         errcode = -EFAULT;
199                                         kfree(*ptr);
200                                         *ptr = NULL;
201                                 } else
202                                         (*ptr)[size] = 0;
203                         }
204                         break;
205                 case 'Q':{
206                                 struct p9_qid *qid =
207                                     va_arg(ap, struct p9_qid *);
208
209                                 errcode = p9pdu_readf(pdu, optional, "bdq",
210                                                       &qid->type, &qid->version,
211                                                       &qid->path);
212                         }
213                         break;
214                 case 'S':{
215                                 struct p9_wstat *stbuf =
216                                     va_arg(ap, struct p9_wstat *);
217
218                                 memset(stbuf, 0, sizeof(struct p9_wstat));
219                                 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
220                                                                         -1;
221                                 errcode =
222                                     p9pdu_readf(pdu, optional,
223                                                 "wwdQdddqssss?sddd",
224                                                 &stbuf->size, &stbuf->type,
225                                                 &stbuf->dev, &stbuf->qid,
226                                                 &stbuf->mode, &stbuf->atime,
227                                                 &stbuf->mtime, &stbuf->length,
228                                                 &stbuf->name, &stbuf->uid,
229                                                 &stbuf->gid, &stbuf->muid,
230                                                 &stbuf->extension,
231                                                 &stbuf->n_uid, &stbuf->n_gid,
232                                                 &stbuf->n_muid);
233                                 if (errcode)
234                                         p9stat_free(stbuf);
235                         }
236                         break;
237                 case 'D':{
238                                 int32_t *count = va_arg(ap, int32_t *);
239                                 void **data = va_arg(ap, void **);
240
241                                 errcode =
242                                     p9pdu_readf(pdu, optional, "d", count);
243                                 if (!errcode) {
244                                         *count =
245                                             MIN(*count,
246                                                 pdu->size - pdu->offset);
247                                         *data = &pdu->sdata[pdu->offset];
248                                 }
249                         }
250                         break;
251                 case 'T':{
252                                 int16_t *nwname = va_arg(ap, int16_t *);
253                                 char ***wnames = va_arg(ap, char ***);
254
255                                 errcode =
256                                     p9pdu_readf(pdu, optional, "w", nwname);
257                                 if (!errcode) {
258                                         *wnames =
259                                             kmalloc(sizeof(char *) * *nwname,
260                                                     GFP_KERNEL);
261                                         if (!*wnames)
262                                                 errcode = -ENOMEM;
263                                 }
264
265                                 if (!errcode) {
266                                         int i;
267
268                                         for (i = 0; i < *nwname; i++) {
269                                                 errcode =
270                                                     p9pdu_readf(pdu, optional,
271                                                                 "s",
272                                                                 &(*wnames)[i]);
273                                                 if (errcode)
274                                                         break;
275                                         }
276                                 }
277
278                                 if (errcode) {
279                                         if (*wnames) {
280                                                 int i;
281
282                                                 for (i = 0; i < *nwname; i++)
283                                                         kfree((*wnames)[i]);
284                                         }
285                                         kfree(*wnames);
286                                         *wnames = NULL;
287                                 }
288                         }
289                         break;
290                 case 'R':{
291                                 int16_t *nwqid = va_arg(ap, int16_t *);
292                                 struct p9_qid **wqids =
293                                     va_arg(ap, struct p9_qid **);
294
295                                 *wqids = NULL;
296
297                                 errcode =
298                                     p9pdu_readf(pdu, optional, "w", nwqid);
299                                 if (!errcode) {
300                                         *wqids =
301                                             kmalloc(*nwqid *
302                                                     sizeof(struct p9_qid),
303                                                     GFP_KERNEL);
304                                         if (*wqids == NULL)
305                                                 errcode = -ENOMEM;
306                                 }
307
308                                 if (!errcode) {
309                                         int i;
310
311                                         for (i = 0; i < *nwqid; i++) {
312                                                 errcode =
313                                                     p9pdu_readf(pdu, optional,
314                                                                 "Q",
315                                                                 &(*wqids)[i]);
316                                                 if (errcode)
317                                                         break;
318                                         }
319                                 }
320
321                                 if (errcode) {
322                                         kfree(*wqids);
323                                         *wqids = NULL;
324                                 }
325                         }
326                         break;
327                 case '?':
328                         if (!optional)
329                                 return 0;
330                         break;
331                 default:
332                         BUG();
333                         break;
334                 }
335
336                 if (errcode)
337                         break;
338         }
339
340         return errcode;
341 }
342
343 int
344 p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
345 {
346         const char *ptr;
347         int errcode = 0;
348
349         for (ptr = fmt; *ptr; ptr++) {
350                 switch (*ptr) {
351                 case 'b':{
352                                 int8_t val = va_arg(ap, int);
353                                 if (pdu_write(pdu, &val, sizeof(val)))
354                                         errcode = -EFAULT;
355                         }
356                         break;
357                 case 'w':{
358                                 int16_t val = va_arg(ap, int);
359                                 if (pdu_write(pdu, &val, sizeof(val)))
360                                         errcode = -EFAULT;
361                         }
362                         break;
363                 case 'd':{
364                                 int32_t val = va_arg(ap, int32_t);
365                                 if (pdu_write(pdu, &val, sizeof(val)))
366                                         errcode = -EFAULT;
367                         }
368                         break;
369                 case 'q':{
370                                 int64_t val = va_arg(ap, int64_t);
371                                 if (pdu_write(pdu, &val, sizeof(val)))
372                                         errcode = -EFAULT;
373                         }
374                         break;
375                 case 's':{
376                                 const char *ptr = va_arg(ap, const char *);
377                                 int16_t len = 0;
378                                 if (ptr)
379                                         len = MIN(strlen(ptr), USHORT_MAX);
380
381                                 errcode = p9pdu_writef(pdu, optional, "w", len);
382                                 if (!errcode && pdu_write(pdu, ptr, len))
383                                         errcode = -EFAULT;
384                         }
385                         break;
386                 case 'Q':{
387                                 const struct p9_qid *qid =
388                                     va_arg(ap, const struct p9_qid *);
389                                 errcode =
390                                     p9pdu_writef(pdu, optional, "bdq",
391                                                  qid->type, qid->version,
392                                                  qid->path);
393                         } break;
394                 case 'S':{
395                                 const struct p9_wstat *stbuf =
396                                     va_arg(ap, const struct p9_wstat *);
397                                 errcode =
398                                     p9pdu_writef(pdu, optional,
399                                                  "wwdQdddqssss?sddd",
400                                                  stbuf->size, stbuf->type,
401                                                  stbuf->dev, &stbuf->qid,
402                                                  stbuf->mode, stbuf->atime,
403                                                  stbuf->mtime, stbuf->length,
404                                                  stbuf->name, stbuf->uid,
405                                                  stbuf->gid, stbuf->muid,
406                                                  stbuf->extension, stbuf->n_uid,
407                                                  stbuf->n_gid, stbuf->n_muid);
408                         } break;
409                 case 'D':{
410                                 int32_t count = va_arg(ap, int32_t);
411                                 const void *data = va_arg(ap, const void *);
412
413                                 errcode =
414                                     p9pdu_writef(pdu, optional, "d", count);
415                                 if (!errcode && pdu_write(pdu, data, count))
416                                         errcode = -EFAULT;
417                         }
418                         break;
419                 case 'U':{
420                                 int32_t count = va_arg(ap, int32_t);
421                                 const char __user *udata =
422                                                 va_arg(ap, const void *);
423                                 errcode =
424                                     p9pdu_writef(pdu, optional, "d", count);
425                                 if (!errcode && pdu_write_u(pdu, udata, count))
426                                         errcode = -EFAULT;
427                         }
428                         break;
429                 case 'T':{
430                                 int16_t nwname = va_arg(ap, int);
431                                 const char **wnames = va_arg(ap, const char **);
432
433                                 errcode =
434                                     p9pdu_writef(pdu, optional, "w", nwname);
435                                 if (!errcode) {
436                                         int i;
437
438                                         for (i = 0; i < nwname; i++) {
439                                                 errcode =
440                                                     p9pdu_writef(pdu, optional,
441                                                                  "s",
442                                                                  wnames[i]);
443                                                 if (errcode)
444                                                         break;
445                                         }
446                                 }
447                         }
448                         break;
449                 case 'R':{
450                                 int16_t nwqid = va_arg(ap, int);
451                                 struct p9_qid *wqids =
452                                     va_arg(ap, struct p9_qid *);
453
454                                 errcode =
455                                     p9pdu_writef(pdu, optional, "w", nwqid);
456                                 if (!errcode) {
457                                         int i;
458
459                                         for (i = 0; i < nwqid; i++) {
460                                                 errcode =
461                                                     p9pdu_writef(pdu, optional,
462                                                                  "Q",
463                                                                  &wqids[i]);
464                                                 if (errcode)
465                                                         break;
466                                         }
467                                 }
468                         }
469                         break;
470                 case '?':
471                         if (!optional)
472                                 return 0;
473                         break;
474                 default:
475                         BUG();
476                         break;
477                 }
478
479                 if (errcode)
480                         break;
481         }
482
483         return errcode;
484 }
485
486 int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...)
487 {
488         va_list ap;
489         int ret;
490
491         va_start(ap, fmt);
492         ret = p9pdu_vreadf(pdu, optional, fmt, ap);
493         va_end(ap);
494
495         return ret;
496 }
497
498 static int
499 p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...)
500 {
501         va_list ap;
502         int ret;
503
504         va_start(ap, fmt);
505         ret = p9pdu_vwritef(pdu, optional, fmt, ap);
506         va_end(ap);
507
508         return ret;
509 }
510
511 int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
512 {
513         struct p9_fcall fake_pdu;
514         int ret;
515
516         fake_pdu.size = len;
517         fake_pdu.capacity = len;
518         fake_pdu.sdata = buf;
519         fake_pdu.offset = 0;
520
521         ret = p9pdu_readf(&fake_pdu, dotu, "S", st);
522         if (ret) {
523                 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
524                 p9pdu_dump(1, &fake_pdu);
525         }
526
527         return ret;
528 }
529 EXPORT_SYMBOL(p9stat_read);
530
531 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
532 {
533         return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
534 }
535
536 int p9pdu_finalize(struct p9_fcall *pdu)
537 {
538         int size = pdu->size;
539         int err;
540
541         pdu->size = 0;
542         err = p9pdu_writef(pdu, 0, "d", size);
543         pdu->size = size;
544
545         if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
546                 p9pdu_dump(0, pdu);
547
548         P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
549                                                         pdu->id, pdu->tag);
550
551         return err;
552 }
553
554 void p9pdu_reset(struct p9_fcall *pdu)
555 {
556         pdu->offset = 0;
557         pdu->size = 0;
558 }