1 #include "lib9.h"
2 #include "fcall.h"
3
4 static
5 uchar*
gstring(uchar * p,uchar * ep,char ** s)6 gstring(uchar *p, uchar *ep, char **s)
7 {
8 uint n;
9
10 if(p+BIT16SZ > ep)
11 return nil;
12 n = GBIT16(p);
13 p += BIT16SZ - 1;
14 if(p+n+1 > ep)
15 return nil;
16 /* move it down, on top of count, to make room for '\0' */
17 memmove(p, p + 1, n);
18 p[n] = '\0';
19 *s = (char*)p;
20 p += n+1;
21 return p;
22 }
23
24 static
25 uchar*
gqid(uchar * p,uchar * ep,Qid * q)26 gqid(uchar *p, uchar *ep, Qid *q)
27 {
28 if(p+QIDSZ > ep)
29 return nil;
30 q->type = GBIT8(p);
31 p += BIT8SZ;
32 q->vers = GBIT32(p);
33 p += BIT32SZ;
34 q->path = GBIT64(p);
35 p += BIT64SZ;
36 return p;
37 }
38
39 /*
40 * no syntactic checks.
41 * three causes for error:
42 * 1. message size field is incorrect
43 * 2. input buffer too short for its own data (counts too long, etc.)
44 * 3. too many names or qids
45 * gqid() and gstring() return nil if they would reach beyond buffer.
46 * main switch statement checks range and also can fall through
47 * to test at end of routine.
48 */
49 uint
convM2S(uchar * ap,uint nap,Fcall * f)50 convM2S(uchar *ap, uint nap, Fcall *f)
51 {
52 uchar *p, *ep;
53 uint i, size;
54
55 p = ap;
56 ep = p + nap;
57
58 if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
59 return 0;
60 size = GBIT32(p);
61 p += BIT32SZ;
62
63 if(size < BIT32SZ+BIT8SZ+BIT16SZ)
64 return 0;
65
66 f->type = GBIT8(p);
67 p += BIT8SZ;
68 f->tag = GBIT16(p);
69 p += BIT16SZ;
70
71 switch(f->type)
72 {
73 default:
74 return 0;
75
76 case Tversion:
77 if(p+BIT32SZ > ep)
78 return 0;
79 f->msize = GBIT32(p);
80 p += BIT32SZ;
81 p = gstring(p, ep, &f->version);
82 break;
83
84 case Tflush:
85 if(p+BIT16SZ > ep)
86 return 0;
87 f->oldtag = GBIT16(p);
88 p += BIT16SZ;
89 break;
90
91 case Tauth:
92 if(p+BIT32SZ > ep)
93 return 0;
94 f->afid = GBIT32(p);
95 p += BIT32SZ;
96 p = gstring(p, ep, &f->uname);
97 if(p == nil)
98 break;
99 p = gstring(p, ep, &f->aname);
100 if(p == nil)
101 break;
102 break;
103
104 case Tattach:
105 if(p+BIT32SZ > ep)
106 return 0;
107 f->fid = GBIT32(p);
108 p += BIT32SZ;
109 if(p+BIT32SZ > ep)
110 return 0;
111 f->afid = GBIT32(p);
112 p += BIT32SZ;
113 p = gstring(p, ep, &f->uname);
114 if(p == nil)
115 break;
116 p = gstring(p, ep, &f->aname);
117 if(p == nil)
118 break;
119 break;
120
121 case Twalk:
122 if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
123 return 0;
124 f->fid = GBIT32(p);
125 p += BIT32SZ;
126 f->newfid = GBIT32(p);
127 p += BIT32SZ;
128 f->nwname = GBIT16(p);
129 p += BIT16SZ;
130 if(f->nwname > MAXWELEM)
131 return 0;
132 for(i=0; i<f->nwname; i++){
133 p = gstring(p, ep, &f->wname[i]);
134 if(p == nil)
135 break;
136 }
137 break;
138
139 case Topen:
140 if(p+BIT32SZ+BIT8SZ > ep)
141 return 0;
142 f->fid = GBIT32(p);
143 p += BIT32SZ;
144 f->mode = GBIT8(p);
145 p += BIT8SZ;
146 break;
147
148 case Tcreate:
149 if(p+BIT32SZ > ep)
150 return 0;
151 f->fid = GBIT32(p);
152 p += BIT32SZ;
153 p = gstring(p, ep, &f->name);
154 if(p == nil)
155 break;
156 if(p+BIT32SZ+BIT8SZ > ep)
157 return 0;
158 f->perm = GBIT32(p);
159 p += BIT32SZ;
160 f->mode = GBIT8(p);
161 p += BIT8SZ;
162 break;
163
164 case Tread:
165 if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
166 return 0;
167 f->fid = GBIT32(p);
168 p += BIT32SZ;
169 f->offset = GBIT64(p);
170 p += BIT64SZ;
171 f->count = GBIT32(p);
172 p += BIT32SZ;
173 break;
174
175 case Twrite:
176 if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
177 return 0;
178 f->fid = GBIT32(p);
179 p += BIT32SZ;
180 f->offset = GBIT64(p);
181 p += BIT64SZ;
182 f->count = GBIT32(p);
183 p += BIT32SZ;
184 if(p+f->count > ep)
185 return 0;
186 f->data = (char*)p;
187 p += f->count;
188 break;
189
190 case Tclunk:
191 case Tremove:
192 if(p+BIT32SZ > ep)
193 return 0;
194 f->fid = GBIT32(p);
195 p += BIT32SZ;
196 break;
197
198 case Tstat:
199 if(p+BIT32SZ > ep)
200 return 0;
201 f->fid = GBIT32(p);
202 p += BIT32SZ;
203 break;
204
205 case Twstat:
206 if(p+BIT32SZ+BIT16SZ > ep)
207 return 0;
208 f->fid = GBIT32(p);
209 p += BIT32SZ;
210 f->nstat = GBIT16(p);
211 p += BIT16SZ;
212 if(p+f->nstat > ep)
213 return 0;
214 f->stat = p;
215 p += f->nstat;
216 break;
217
218 /*
219 */
220 case Rversion:
221 if(p+BIT32SZ > ep)
222 return 0;
223 f->msize = GBIT32(p);
224 p += BIT32SZ;
225 p = gstring(p, ep, &f->version);
226 break;
227
228 case Rerror:
229 p = gstring(p, ep, &f->ename);
230 break;
231
232 case Rflush:
233 break;
234
235 case Rauth:
236 p = gqid(p, ep, &f->aqid);
237 if(p == nil)
238 break;
239 break;
240
241 case Rattach:
242 p = gqid(p, ep, &f->qid);
243 if(p == nil)
244 break;
245 break;
246
247 case Rwalk:
248 if(p+BIT16SZ > ep)
249 return 0;
250 f->nwqid = GBIT16(p);
251 p += BIT16SZ;
252 if(f->nwqid > MAXWELEM)
253 return 0;
254 for(i=0; i<f->nwqid; i++){
255 p = gqid(p, ep, &f->wqid[i]);
256 if(p == nil)
257 break;
258 }
259 break;
260
261 case Ropen:
262 case Rcreate:
263 p = gqid(p, ep, &f->qid);
264 if(p == nil)
265 break;
266 if(p+BIT32SZ > ep)
267 return 0;
268 f->iounit = GBIT32(p);
269 p += BIT32SZ;
270 break;
271
272 case Rread:
273 if(p+BIT32SZ > ep)
274 return 0;
275 f->count = GBIT32(p);
276 p += BIT32SZ;
277 if(p+f->count > ep)
278 return 0;
279 f->data = (char*)p;
280 p += f->count;
281 break;
282
283 case Rwrite:
284 if(p+BIT32SZ > ep)
285 return 0;
286 f->count = GBIT32(p);
287 p += BIT32SZ;
288 break;
289
290 case Rclunk:
291 case Rremove:
292 break;
293
294 case Rstat:
295 if(p+BIT16SZ > ep)
296 return 0;
297 f->nstat = GBIT16(p);
298 p += BIT16SZ;
299 if(p+f->nstat > ep)
300 return 0;
301 f->stat = p;
302 p += f->nstat;
303 break;
304
305 case Rwstat:
306 break;
307 }
308
309 if(p==nil || p>ep)
310 return 0;
311 if(ap+size == p)
312 return size;
313 return 0;
314 }
315