9ns: Fix issues with can_have_children
[akaros.git] / kern / src / ns / convM2S.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <slab.h>
30 #include <kmalloc.h>
31 #include <kref.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <assert.h>
35 #include <error.h>
36 #include <cpio.h>
37 #include <pmap.h>
38 #include <smp.h>
39 #include <net/ip.h>
40
41 static
42 uint8_t *gstring(uint8_t * p, uint8_t * ep, char **s)
43 {
44         unsigned int n;
45
46         if (p + BIT16SZ > ep)
47                 return NULL;
48         n = GBIT16(p);
49         p += BIT16SZ - 1;
50         if (p + n + 1 > ep)
51                 return NULL;
52         /* move it down, on top of count, to make room for '\0' */
53         memmove(p, p + 1, n);
54         p[n] = '\0';
55         *s = (char *)p;
56         p += n + 1;
57         return p;
58 }
59
60 static
61 uint8_t *gqid(uint8_t * p, uint8_t * ep, struct qid *q)
62 {
63         if (p + QIDSZ > ep)
64                 return NULL;
65         q->type = GBIT8(p);
66         p += BIT8SZ;
67         q->vers = GBIT32(p);
68         p += BIT32SZ;
69         q->path = GBIT64(p);
70         p += BIT64SZ;
71         return p;
72 }
73
74 /* This initializes a dir to "don't touch" values.  These fields are ignored on
75  * a wstat. */
76 void init_empty_dir(struct dir *d)
77 {
78         d->type = ~0;
79         d->dev = ~0;
80         d->qid.path = ~0;
81         d->qid.vers = ~0;
82         d->qid.type = ~0;
83         d->mode = ~0;
84         d->length = ~0;
85         d->name = "";
86         d->uid = "";
87         d->gid = "";
88         d->muid = "";
89         d->ext = "";
90         d->n_uid = ~0;
91         d->n_gid = ~0;
92         d->n_muid = ~0;
93         d->atime.tv_sec = ~0;
94         d->btime.tv_sec = ~0;
95         d->ctime.tv_sec = ~0;
96         d->mtime.tv_sec = ~0;
97         /* We don't look at tv_nsec to determine whether or not the field is "don't
98          * touch".  This way, all nsecs are normal. */
99         d->atime.tv_nsec = 0;
100         d->btime.tv_nsec = 0;
101         d->ctime.tv_nsec = 0;
102         d->mtime.tv_nsec = 0;
103 }
104
105 /*
106  * no syntactic checks.
107  * three causes for error:
108  *  1. message size field is incorrect
109  *  2. input buffer too short for its own data (counts too long, etc.)
110  *  3. too many names or qids
111  * gqid() and gstring() return NULL if they would reach beyond buffer.
112  * main switch statement checks range and also can fall through
113  * to test at end of routine.
114  */
115 unsigned int convM2S(uint8_t * ap, unsigned int nap, struct fcall *f)
116 {
117         uint8_t *p, *ep;
118         unsigned int i, size;
119
120         p = ap;
121         ep = p + nap;
122
123         if (p + BIT32SZ + BIT8SZ + BIT16SZ > ep)
124                 return 0;
125         size = GBIT32(p);
126         p += BIT32SZ;
127
128         if (size < BIT32SZ + BIT8SZ + BIT16SZ)
129                 return 0;
130
131         f->type = GBIT8(p);
132         p += BIT8SZ;
133         f->tag = GBIT16(p);
134         p += BIT16SZ;
135
136         switch (f->type) {
137                 default:
138                         return 0;
139
140                 case Tversion:
141                         if (p + BIT32SZ > ep)
142                                 return 0;
143                         f->msize = GBIT32(p);
144                         p += BIT32SZ;
145                         p = gstring(p, ep, &f->version);
146                         break;
147
148                 case Tflush:
149                         if (p + BIT16SZ > ep)
150                                 return 0;
151                         f->oldtag = GBIT16(p);
152                         p += BIT16SZ;
153                         break;
154
155                 case Tauth:
156                         if (p + BIT32SZ > ep)
157                                 return 0;
158                         f->afid = GBIT32(p);
159                         p += BIT32SZ;
160                         p = gstring(p, ep, &f->uname);
161                         if (p == NULL)
162                                 break;
163                         p = gstring(p, ep, &f->aname);
164                         if (p == NULL)
165                                 break;
166                         break;
167
168                 case Tattach:
169                         if (p + BIT32SZ > ep)
170                                 return 0;
171                         f->fid = GBIT32(p);
172                         p += BIT32SZ;
173                         if (p + BIT32SZ > ep)
174                                 return 0;
175                         f->afid = GBIT32(p);
176                         p += BIT32SZ;
177                         p = gstring(p, ep, &f->uname);
178                         if (p == NULL)
179                                 break;
180                         p = gstring(p, ep, &f->aname);
181                         if (p == NULL)
182                                 break;
183                         break;
184
185                 case Twalk:
186                         if (p + BIT32SZ + BIT32SZ + BIT16SZ > ep)
187                                 return 0;
188                         f->fid = GBIT32(p);
189                         p += BIT32SZ;
190                         f->newfid = GBIT32(p);
191                         p += BIT32SZ;
192                         f->nwname = GBIT16(p);
193                         p += BIT16SZ;
194                         if (f->nwname > MAXWELEM)
195                                 return 0;
196                         for (i = 0; i < f->nwname; i++) {
197                                 p = gstring(p, ep, &f->wname[i]);
198                                 if (p == NULL)
199                                         break;
200                         }
201                         break;
202
203                 case Topen:
204                         if (p + BIT32SZ + BIT8SZ > ep)
205                                 return 0;
206                         f->fid = GBIT32(p);
207                         p += BIT32SZ;
208                         f->mode = GBIT8(p);
209                         p += BIT8SZ;
210                         break;
211
212                 case Tcreate:
213                         if (p + BIT32SZ > ep)
214                                 return 0;
215                         f->fid = GBIT32(p);
216                         p += BIT32SZ;
217                         p = gstring(p, ep, &f->name);
218                         if (p == NULL)
219                                 break;
220                         if (p + BIT32SZ + BIT8SZ > ep)
221                                 return 0;
222                         f->perm = GBIT32(p);
223                         p += BIT32SZ;
224                         f->mode = GBIT8(p);
225                         p += BIT8SZ;
226                         break;
227
228                 case Tread:
229                         if (p + BIT32SZ + BIT64SZ + BIT32SZ > ep)
230                                 return 0;
231                         f->fid = GBIT32(p);
232                         p += BIT32SZ;
233                         f->offset = GBIT64(p);
234                         p += BIT64SZ;
235                         f->count = GBIT32(p);
236                         p += BIT32SZ;
237                         break;
238
239                 case Twrite:
240                         if (p + BIT32SZ + BIT64SZ + BIT32SZ > ep)
241                                 return 0;
242                         f->fid = GBIT32(p);
243                         p += BIT32SZ;
244                         f->offset = GBIT64(p);
245                         p += BIT64SZ;
246                         f->count = GBIT32(p);
247                         p += BIT32SZ;
248                         if (p + f->count > ep)
249                                 return 0;
250                         f->data = (char *)p;
251                         p += f->count;
252                         break;
253
254                 case Tclunk:
255                 case Tremove:
256                         if (p + BIT32SZ > ep)
257                                 return 0;
258                         f->fid = GBIT32(p);
259                         p += BIT32SZ;
260                         break;
261
262                 case Tstat:
263                         if (p + BIT32SZ > ep)
264                                 return 0;
265                         f->fid = GBIT32(p);
266                         p += BIT32SZ;
267                         break;
268
269                 case Twstat:
270                         if (p + BIT32SZ + BIT16SZ > ep)
271                                 return 0;
272                         f->fid = GBIT32(p);
273                         p += BIT32SZ;
274                         f->nstat = GBIT16(p);
275                         p += BIT16SZ;
276                         if (p + f->nstat > ep)
277                                 return 0;
278                         f->stat = p;
279                         p += f->nstat;
280                         break;
281
282 /*
283  */
284                 case Rversion:
285                         if (p + BIT32SZ > ep)
286                                 return 0;
287                         f->msize = GBIT32(p);
288                         p += BIT32SZ;
289                         p = gstring(p, ep, &f->version);
290                         break;
291
292                 case Rerror:
293                         p = gstring(p, ep, &f->ename);
294                         break;
295
296                 case Rflush:
297                         break;
298
299                 case Rauth:
300                         p = gqid(p, ep, &f->aqid);
301                         if (p == NULL)
302                                 break;
303                         break;
304
305                 case Rattach:
306                         p = gqid(p, ep, &f->qid);
307                         if (p == NULL)
308                                 break;
309                         break;
310
311                 case Rwalk:
312                         if (p + BIT16SZ > ep)
313                                 return 0;
314                         f->nwqid = GBIT16(p);
315                         p += BIT16SZ;
316                         if (f->nwqid > MAXWELEM)
317                                 return 0;
318                         for (i = 0; i < f->nwqid; i++) {
319                                 p = gqid(p, ep, &f->wqid[i]);
320                                 if (p == NULL)
321                                         break;
322                         }
323                         break;
324
325                 case Ropen:
326                 case Rcreate:
327                         p = gqid(p, ep, &f->qid);
328                         if (p == NULL)
329                                 break;
330                         if (p + BIT32SZ > ep)
331                                 return 0;
332                         f->iounit = GBIT32(p);
333                         p += BIT32SZ;
334                         break;
335
336                 case Rread:
337                         if (p + BIT32SZ > ep)
338                                 return 0;
339                         f->count = GBIT32(p);
340                         p += BIT32SZ;
341                         if (p + f->count > ep)
342                                 return 0;
343                         f->data = (char *)p;
344                         p += f->count;
345                         break;
346
347                 case Rwrite:
348                         if (p + BIT32SZ > ep)
349                                 return 0;
350                         f->count = GBIT32(p);
351                         p += BIT32SZ;
352                         break;
353
354                 case Rclunk:
355                 case Rremove:
356                         break;
357
358                 case Rstat:
359                         if (p + BIT16SZ > ep)
360                                 return 0;
361                         f->nstat = GBIT16(p);
362                         p += BIT16SZ;
363                         if (p + f->nstat > ep)
364                                 return 0;
365                         f->stat = p;
366                         p += f->nstat;
367                         break;
368
369                 case Rwstat:
370                         break;
371         }
372
373         if (p == NULL || p > ep)
374                 return 0;
375         if (ap + size == p)
376                 return size;
377         return 0;
378 }