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