13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <fcall.h>
43e12c5d1SDavid du Colombier
5*9a747e4fSDavid du Colombier static
6*9a747e4fSDavid du Colombier uchar*
gstring(uchar * p,uchar * ep,char ** s)7*9a747e4fSDavid du Colombier gstring(uchar *p, uchar *ep, char **s)
83e12c5d1SDavid du Colombier {
9*9a747e4fSDavid du Colombier uint n;
103e12c5d1SDavid du Colombier
11*9a747e4fSDavid du Colombier if(p+BIT16SZ > ep)
12*9a747e4fSDavid du Colombier return nil;
13*9a747e4fSDavid du Colombier n = GBIT16(p);
14*9a747e4fSDavid du Colombier p += BIT16SZ - 1;
15*9a747e4fSDavid du Colombier if(p+n+1 > ep)
16*9a747e4fSDavid du Colombier return nil;
17*9a747e4fSDavid du Colombier /* move it down, on top of count, to make room for '\0' */
18*9a747e4fSDavid du Colombier memmove(p, p + 1, n);
19*9a747e4fSDavid du Colombier p[n] = '\0';
20*9a747e4fSDavid du Colombier *s = (char*)p;
21*9a747e4fSDavid du Colombier p += n+1;
22*9a747e4fSDavid du Colombier return p;
23*9a747e4fSDavid du Colombier }
24*9a747e4fSDavid du Colombier
25*9a747e4fSDavid du Colombier static
26*9a747e4fSDavid du Colombier uchar*
gqid(uchar * p,uchar * ep,Qid * q)27*9a747e4fSDavid du Colombier gqid(uchar *p, uchar *ep, Qid *q)
28*9a747e4fSDavid du Colombier {
29*9a747e4fSDavid du Colombier if(p+QIDSZ > ep)
30*9a747e4fSDavid du Colombier return nil;
31*9a747e4fSDavid du Colombier q->type = GBIT8(p);
32*9a747e4fSDavid du Colombier p += BIT8SZ;
33*9a747e4fSDavid du Colombier q->vers = GBIT32(p);
34*9a747e4fSDavid du Colombier p += BIT32SZ;
35*9a747e4fSDavid du Colombier q->path = GBIT64(p);
36*9a747e4fSDavid du Colombier p += BIT64SZ;
37*9a747e4fSDavid du Colombier return p;
38*9a747e4fSDavid du Colombier }
39*9a747e4fSDavid du Colombier
40*9a747e4fSDavid du Colombier /*
41*9a747e4fSDavid du Colombier * no syntactic checks.
42*9a747e4fSDavid du Colombier * three causes for error:
43*9a747e4fSDavid du Colombier * 1. message size field is incorrect
44*9a747e4fSDavid du Colombier * 2. input buffer too short for its own data (counts too long, etc.)
45*9a747e4fSDavid du Colombier * 3. too many names or qids
46*9a747e4fSDavid du Colombier * gqid() and gstring() return nil if they would reach beyond buffer.
47*9a747e4fSDavid du Colombier * main switch statement checks range and also can fall through
48*9a747e4fSDavid du Colombier * to test at end of routine.
49*9a747e4fSDavid du Colombier */
50*9a747e4fSDavid du Colombier uint
convM2S(uchar * ap,uint nap,Fcall * f)51*9a747e4fSDavid du Colombier convM2S(uchar *ap, uint nap, Fcall *f)
52*9a747e4fSDavid du Colombier {
53*9a747e4fSDavid du Colombier uchar *p, *ep;
54*9a747e4fSDavid du Colombier uint i, size;
55*9a747e4fSDavid du Colombier
56*9a747e4fSDavid du Colombier p = ap;
57*9a747e4fSDavid du Colombier ep = p + nap;
58*9a747e4fSDavid du Colombier
59*9a747e4fSDavid du Colombier if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
60*9a747e4fSDavid du Colombier return 0;
61*9a747e4fSDavid du Colombier size = GBIT32(p);
62*9a747e4fSDavid du Colombier p += BIT32SZ;
63*9a747e4fSDavid du Colombier
64*9a747e4fSDavid du Colombier if(size < BIT32SZ+BIT8SZ+BIT16SZ)
65*9a747e4fSDavid du Colombier return 0;
66*9a747e4fSDavid du Colombier
67*9a747e4fSDavid du Colombier f->type = GBIT8(p);
68*9a747e4fSDavid du Colombier p += BIT8SZ;
69*9a747e4fSDavid du Colombier f->tag = GBIT16(p);
70*9a747e4fSDavid du Colombier p += BIT16SZ;
71*9a747e4fSDavid du Colombier
723e12c5d1SDavid du Colombier switch(f->type)
733e12c5d1SDavid du Colombier {
743e12c5d1SDavid du Colombier default:
753e12c5d1SDavid du Colombier return 0;
763e12c5d1SDavid du Colombier
77*9a747e4fSDavid du Colombier case Tversion:
78*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
79*9a747e4fSDavid du Colombier return 0;
80*9a747e4fSDavid du Colombier f->msize = GBIT32(p);
81*9a747e4fSDavid du Colombier p += BIT32SZ;
82*9a747e4fSDavid du Colombier p = gstring(p, ep, &f->version);
833e12c5d1SDavid du Colombier break;
843e12c5d1SDavid du Colombier
853e12c5d1SDavid du Colombier case Tflush:
86*9a747e4fSDavid du Colombier if(p+BIT16SZ > ep)
87*9a747e4fSDavid du Colombier return 0;
88*9a747e4fSDavid du Colombier f->oldtag = GBIT16(p);
89*9a747e4fSDavid du Colombier p += BIT16SZ;
90219b2ee8SDavid du Colombier break;
91219b2ee8SDavid du Colombier
923e12c5d1SDavid du Colombier case Tauth:
93*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
94*9a747e4fSDavid du Colombier return 0;
95*9a747e4fSDavid du Colombier f->afid = GBIT32(p);
96*9a747e4fSDavid du Colombier p += BIT32SZ;
97*9a747e4fSDavid du Colombier p = gstring(p, ep, &f->uname);
98*9a747e4fSDavid du Colombier if(p == nil)
99*9a747e4fSDavid du Colombier break;
100*9a747e4fSDavid du Colombier p = gstring(p, ep, &f->aname);
101*9a747e4fSDavid du Colombier if(p == nil)
102*9a747e4fSDavid du Colombier break;
1033e12c5d1SDavid du Colombier break;
1043e12c5d1SDavid du Colombier
105*9a747e4fSDavid du Colombier case Tattach:
106*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
107*9a747e4fSDavid du Colombier return 0;
108*9a747e4fSDavid du Colombier f->fid = GBIT32(p);
109*9a747e4fSDavid du Colombier p += BIT32SZ;
110*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
111*9a747e4fSDavid du Colombier return 0;
112*9a747e4fSDavid du Colombier f->afid = GBIT32(p);
113*9a747e4fSDavid du Colombier p += BIT32SZ;
114*9a747e4fSDavid du Colombier p = gstring(p, ep, &f->uname);
115*9a747e4fSDavid du Colombier if(p == nil)
116*9a747e4fSDavid du Colombier break;
117*9a747e4fSDavid du Colombier p = gstring(p, ep, &f->aname);
118*9a747e4fSDavid du Colombier if(p == nil)
119*9a747e4fSDavid du Colombier break;
1203e12c5d1SDavid du Colombier break;
1213e12c5d1SDavid du Colombier
1223e12c5d1SDavid du Colombier case Twalk:
123*9a747e4fSDavid du Colombier if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
124*9a747e4fSDavid du Colombier return 0;
125*9a747e4fSDavid du Colombier f->fid = GBIT32(p);
126*9a747e4fSDavid du Colombier p += BIT32SZ;
127*9a747e4fSDavid du Colombier f->newfid = GBIT32(p);
128*9a747e4fSDavid du Colombier p += BIT32SZ;
129*9a747e4fSDavid du Colombier f->nwname = GBIT16(p);
130*9a747e4fSDavid du Colombier p += BIT16SZ;
131*9a747e4fSDavid du Colombier if(f->nwname > MAXWELEM)
132*9a747e4fSDavid du Colombier return 0;
133*9a747e4fSDavid du Colombier for(i=0; i<f->nwname; i++){
134*9a747e4fSDavid du Colombier p = gstring(p, ep, &f->wname[i]);
135*9a747e4fSDavid du Colombier if(p == nil)
136*9a747e4fSDavid du Colombier break;
137*9a747e4fSDavid du Colombier }
1383e12c5d1SDavid du Colombier break;
1393e12c5d1SDavid du Colombier
1403e12c5d1SDavid du Colombier case Topen:
141*9a747e4fSDavid du Colombier if(p+BIT32SZ+BIT8SZ > ep)
142*9a747e4fSDavid du Colombier return 0;
143*9a747e4fSDavid du Colombier f->fid = GBIT32(p);
144*9a747e4fSDavid du Colombier p += BIT32SZ;
145*9a747e4fSDavid du Colombier f->mode = GBIT8(p);
146*9a747e4fSDavid du Colombier p += BIT8SZ;
1473e12c5d1SDavid du Colombier break;
1483e12c5d1SDavid du Colombier
1493e12c5d1SDavid du Colombier case Tcreate:
150*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
151*9a747e4fSDavid du Colombier return 0;
152*9a747e4fSDavid du Colombier f->fid = GBIT32(p);
153*9a747e4fSDavid du Colombier p += BIT32SZ;
154*9a747e4fSDavid du Colombier p = gstring(p, ep, &f->name);
155*9a747e4fSDavid du Colombier if(p == nil)
156*9a747e4fSDavid du Colombier break;
157*9a747e4fSDavid du Colombier if(p+BIT32SZ+BIT8SZ > ep)
158*9a747e4fSDavid du Colombier return 0;
159*9a747e4fSDavid du Colombier f->perm = GBIT32(p);
160*9a747e4fSDavid du Colombier p += BIT32SZ;
161*9a747e4fSDavid du Colombier f->mode = GBIT8(p);
162*9a747e4fSDavid du Colombier p += BIT8SZ;
1633e12c5d1SDavid du Colombier break;
1643e12c5d1SDavid du Colombier
1653e12c5d1SDavid du Colombier case Tread:
166*9a747e4fSDavid du Colombier if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
167*9a747e4fSDavid du Colombier return 0;
168*9a747e4fSDavid du Colombier f->fid = GBIT32(p);
169*9a747e4fSDavid du Colombier p += BIT32SZ;
170*9a747e4fSDavid du Colombier f->offset = GBIT64(p);
171*9a747e4fSDavid du Colombier p += BIT64SZ;
172*9a747e4fSDavid du Colombier f->count = GBIT32(p);
173*9a747e4fSDavid du Colombier p += BIT32SZ;
1743e12c5d1SDavid du Colombier break;
1753e12c5d1SDavid du Colombier
1763e12c5d1SDavid du Colombier case Twrite:
177*9a747e4fSDavid du Colombier if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
178*9a747e4fSDavid du Colombier return 0;
179*9a747e4fSDavid du Colombier f->fid = GBIT32(p);
180*9a747e4fSDavid du Colombier p += BIT32SZ;
181*9a747e4fSDavid du Colombier f->offset = GBIT64(p);
182*9a747e4fSDavid du Colombier p += BIT64SZ;
183*9a747e4fSDavid du Colombier f->count = GBIT32(p);
184*9a747e4fSDavid du Colombier p += BIT32SZ;
185*9a747e4fSDavid du Colombier if(p+f->count > ep)
186*9a747e4fSDavid du Colombier return 0;
187*9a747e4fSDavid du Colombier f->data = (char*)p;
188*9a747e4fSDavid du Colombier p += f->count;
1893e12c5d1SDavid du Colombier break;
1903e12c5d1SDavid du Colombier
1913e12c5d1SDavid du Colombier case Tclunk:
1923e12c5d1SDavid du Colombier case Tremove:
193*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
194*9a747e4fSDavid du Colombier return 0;
195*9a747e4fSDavid du Colombier f->fid = GBIT32(p);
196*9a747e4fSDavid du Colombier p += BIT32SZ;
1973e12c5d1SDavid du Colombier break;
1983e12c5d1SDavid du Colombier
1993e12c5d1SDavid du Colombier case Tstat:
200*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
201*9a747e4fSDavid du Colombier return 0;
202*9a747e4fSDavid du Colombier f->fid = GBIT32(p);
203*9a747e4fSDavid du Colombier p += BIT32SZ;
2043e12c5d1SDavid du Colombier break;
2053e12c5d1SDavid du Colombier
2063e12c5d1SDavid du Colombier case Twstat:
207*9a747e4fSDavid du Colombier if(p+BIT32SZ+BIT16SZ > ep)
208*9a747e4fSDavid du Colombier return 0;
209*9a747e4fSDavid du Colombier f->fid = GBIT32(p);
210*9a747e4fSDavid du Colombier p += BIT32SZ;
211*9a747e4fSDavid du Colombier f->nstat = GBIT16(p);
212*9a747e4fSDavid du Colombier p += BIT16SZ;
213*9a747e4fSDavid du Colombier if(p+f->nstat > ep)
214*9a747e4fSDavid du Colombier return 0;
215*9a747e4fSDavid du Colombier f->stat = p;
216*9a747e4fSDavid du Colombier p += f->nstat;
2173e12c5d1SDavid du Colombier break;
2183e12c5d1SDavid du Colombier
2193e12c5d1SDavid du Colombier /*
2203e12c5d1SDavid du Colombier */
221*9a747e4fSDavid du Colombier case Rversion:
222*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
223*9a747e4fSDavid du Colombier return 0;
224*9a747e4fSDavid du Colombier f->msize = GBIT32(p);
225*9a747e4fSDavid du Colombier p += BIT32SZ;
226*9a747e4fSDavid du Colombier p = gstring(p, ep, &f->version);
2273e12c5d1SDavid du Colombier break;
2283e12c5d1SDavid du Colombier
2293e12c5d1SDavid du Colombier case Rerror:
230*9a747e4fSDavid du Colombier p = gstring(p, ep, &f->ename);
2313e12c5d1SDavid du Colombier break;
2323e12c5d1SDavid du Colombier
2333e12c5d1SDavid du Colombier case Rflush:
2343e12c5d1SDavid du Colombier break;
2353e12c5d1SDavid du Colombier
2363e12c5d1SDavid du Colombier case Rauth:
237*9a747e4fSDavid du Colombier p = gqid(p, ep, &f->aqid);
238*9a747e4fSDavid du Colombier if(p == nil)
239*9a747e4fSDavid du Colombier break;
2403e12c5d1SDavid du Colombier break;
2413e12c5d1SDavid du Colombier
242*9a747e4fSDavid du Colombier case Rattach:
243*9a747e4fSDavid du Colombier p = gqid(p, ep, &f->qid);
244*9a747e4fSDavid du Colombier if(p == nil)
245*9a747e4fSDavid du Colombier break;
2463e12c5d1SDavid du Colombier break;
2473e12c5d1SDavid du Colombier
2483e12c5d1SDavid du Colombier case Rwalk:
249*9a747e4fSDavid du Colombier if(p+BIT16SZ > ep)
250*9a747e4fSDavid du Colombier return 0;
251*9a747e4fSDavid du Colombier f->nwqid = GBIT16(p);
252*9a747e4fSDavid du Colombier p += BIT16SZ;
253*9a747e4fSDavid du Colombier if(f->nwqid > MAXWELEM)
254*9a747e4fSDavid du Colombier return 0;
255*9a747e4fSDavid du Colombier for(i=0; i<f->nwqid; i++){
256*9a747e4fSDavid du Colombier p = gqid(p, ep, &f->wqid[i]);
257*9a747e4fSDavid du Colombier if(p == nil)
258*9a747e4fSDavid du Colombier break;
259*9a747e4fSDavid du Colombier }
2603e12c5d1SDavid du Colombier break;
2613e12c5d1SDavid du Colombier
2623e12c5d1SDavid du Colombier case Ropen:
2633e12c5d1SDavid du Colombier case Rcreate:
264*9a747e4fSDavid du Colombier p = gqid(p, ep, &f->qid);
265*9a747e4fSDavid du Colombier if(p == nil)
266*9a747e4fSDavid du Colombier break;
267*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
268*9a747e4fSDavid du Colombier return 0;
269*9a747e4fSDavid du Colombier f->iounit = GBIT32(p);
270*9a747e4fSDavid du Colombier p += BIT32SZ;
2713e12c5d1SDavid du Colombier break;
2723e12c5d1SDavid du Colombier
2733e12c5d1SDavid du Colombier case Rread:
274*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
275*9a747e4fSDavid du Colombier return 0;
276*9a747e4fSDavid du Colombier f->count = GBIT32(p);
277*9a747e4fSDavid du Colombier p += BIT32SZ;
278*9a747e4fSDavid du Colombier if(p+f->count > ep)
279*9a747e4fSDavid du Colombier return 0;
280*9a747e4fSDavid du Colombier f->data = (char*)p;
281*9a747e4fSDavid du Colombier p += f->count;
2823e12c5d1SDavid du Colombier break;
2833e12c5d1SDavid du Colombier
2843e12c5d1SDavid du Colombier case Rwrite:
285*9a747e4fSDavid du Colombier if(p+BIT32SZ > ep)
286*9a747e4fSDavid du Colombier return 0;
287*9a747e4fSDavid du Colombier f->count = GBIT32(p);
288*9a747e4fSDavid du Colombier p += BIT32SZ;
2893e12c5d1SDavid du Colombier break;
2903e12c5d1SDavid du Colombier
2913e12c5d1SDavid du Colombier case Rclunk:
2923e12c5d1SDavid du Colombier case Rremove:
2933e12c5d1SDavid du Colombier break;
2943e12c5d1SDavid du Colombier
2953e12c5d1SDavid du Colombier case Rstat:
296*9a747e4fSDavid du Colombier if(p+BIT16SZ > ep)
297*9a747e4fSDavid du Colombier return 0;
298*9a747e4fSDavid du Colombier f->nstat = GBIT16(p);
299*9a747e4fSDavid du Colombier p += BIT16SZ;
300*9a747e4fSDavid du Colombier if(p+f->nstat > ep)
301*9a747e4fSDavid du Colombier return 0;
302*9a747e4fSDavid du Colombier f->stat = p;
303*9a747e4fSDavid du Colombier p += f->nstat;
3043e12c5d1SDavid du Colombier break;
3053e12c5d1SDavid du Colombier
3063e12c5d1SDavid du Colombier case Rwstat:
3073e12c5d1SDavid du Colombier break;
3083e12c5d1SDavid du Colombier }
309*9a747e4fSDavid du Colombier
310*9a747e4fSDavid du Colombier if(p==nil || p>ep)
311*9a747e4fSDavid du Colombier return 0;
312*9a747e4fSDavid du Colombier if(ap+size == p)
313*9a747e4fSDavid du Colombier return size;
3143e12c5d1SDavid du Colombier return 0;
3153e12c5d1SDavid du Colombier }
316