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 		f->uidnum = NOUID;
104 		break;
105 
106 	case Tattach:
107 		if(p+BIT32SZ > ep)
108 			return 0;
109 		f->fid = GBIT32(p);
110 		p += BIT32SZ;
111 		if(p+BIT32SZ > ep)
112 			return 0;
113 		f->afid = GBIT32(p);
114 		p += BIT32SZ;
115 		p = gstring(p, ep, &f->uname);
116 		if(p == nil)
117 			break;
118 		p = gstring(p, ep, &f->aname);
119 		if(p == nil)
120 			break;
121 		f->uidnum = NOUID;
122 		break;
123 
124 	case Twalk:
125 		if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
126 			return 0;
127 		f->fid = GBIT32(p);
128 		p += BIT32SZ;
129 		f->newfid = GBIT32(p);
130 		p += BIT32SZ;
131 		f->nwname = GBIT16(p);
132 		p += BIT16SZ;
133 		if(f->nwname > MAXWELEM)
134 			return 0;
135 		for(i=0; i<f->nwname; i++){
136 			p = gstring(p, ep, &f->wname[i]);
137 			if(p == nil)
138 				break;
139 		}
140 		break;
141 
142 	case Topen:
143 	case Topenfd:
144 		if(p+BIT32SZ+BIT8SZ > ep)
145 			return 0;
146 		f->fid = GBIT32(p);
147 		p += BIT32SZ;
148 		f->mode = GBIT8(p);
149 		p += BIT8SZ;
150 		break;
151 
152 	case Tcreate:
153 		if(p+BIT32SZ > ep)
154 			return 0;
155 		f->fid = GBIT32(p);
156 		p += BIT32SZ;
157 		p = gstring(p, ep, &f->name);
158 		if(p == nil)
159 			break;
160 		if(p+BIT32SZ+BIT8SZ > ep)
161 			return 0;
162 		f->perm = GBIT32(p);
163 		p += BIT32SZ;
164 		f->mode = GBIT8(p);
165 		p += BIT8SZ;
166 		break;
167 
168 	case Tread:
169 		if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
170 			return 0;
171 		f->fid = GBIT32(p);
172 		p += BIT32SZ;
173 		f->offset = GBIT64(p);
174 		p += BIT64SZ;
175 		f->count = GBIT32(p);
176 		p += BIT32SZ;
177 		break;
178 
179 	case Twrite:
180 		if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
181 			return 0;
182 		f->fid = GBIT32(p);
183 		p += BIT32SZ;
184 		f->offset = GBIT64(p);
185 		p += BIT64SZ;
186 		f->count = GBIT32(p);
187 		p += BIT32SZ;
188 		if(p+f->count > ep)
189 			return 0;
190 		f->data = (char*)p;
191 		p += f->count;
192 		break;
193 
194 	case Tclunk:
195 	case Tremove:
196 		if(p+BIT32SZ > ep)
197 			return 0;
198 		f->fid = GBIT32(p);
199 		p += BIT32SZ;
200 		break;
201 
202 	case Tstat:
203 		if(p+BIT32SZ > ep)
204 			return 0;
205 		f->fid = GBIT32(p);
206 		p += BIT32SZ;
207 		break;
208 
209 	case Twstat:
210 		if(p+BIT32SZ+BIT16SZ > ep)
211 			return 0;
212 		f->fid = GBIT32(p);
213 		p += BIT32SZ;
214 		f->nstat = GBIT16(p);
215 		p += BIT16SZ;
216 		if(p+f->nstat > ep)
217 			return 0;
218 		f->stat = p;
219 		p += f->nstat;
220 		break;
221 
222 /*
223  */
224 	case Rversion:
225 		if(p+BIT32SZ > ep)
226 			return 0;
227 		f->msize = GBIT32(p);
228 		p += BIT32SZ;
229 		p = gstring(p, ep, &f->version);
230 		break;
231 
232 	case Rerror:
233 		p = gstring(p, ep, &f->ename);
234 		f->errornum = 0;
235 		break;
236 
237 	case Rflush:
238 		break;
239 
240 	case Rauth:
241 		p = gqid(p, ep, &f->aqid);
242 		if(p == nil)
243 			break;
244 		break;
245 
246 	case Rattach:
247 		p = gqid(p, ep, &f->qid);
248 		if(p == nil)
249 			break;
250 		break;
251 
252 	case Rwalk:
253 		if(p+BIT16SZ > ep)
254 			return 0;
255 		f->nwqid = GBIT16(p);
256 		p += BIT16SZ;
257 		if(f->nwqid > MAXWELEM)
258 			return 0;
259 		for(i=0; i<f->nwqid; i++){
260 			p = gqid(p, ep, &f->wqid[i]);
261 			if(p == nil)
262 				break;
263 		}
264 		break;
265 
266 	case Ropen:
267 	case Ropenfd:
268 	case Rcreate:
269 		p = gqid(p, ep, &f->qid);
270 		if(p == nil)
271 			break;
272 		if(p+BIT32SZ > ep)
273 			return 0;
274 		f->iounit = GBIT32(p);
275 		p += BIT32SZ;
276 		if(f->type == Ropenfd){
277 			if(p+BIT32SZ > ep)
278 				return 0;
279 			f->unixfd = GBIT32(p);
280 			p += BIT32SZ;
281 		}
282 		break;
283 
284 	case Rread:
285 		if(p+BIT32SZ > ep)
286 			return 0;
287 		f->count = GBIT32(p);
288 		p += BIT32SZ;
289 		if(p+f->count > ep)
290 			return 0;
291 		f->data = (char*)p;
292 		p += f->count;
293 		break;
294 
295 	case Rwrite:
296 		if(p+BIT32SZ > ep)
297 			return 0;
298 		f->count = GBIT32(p);
299 		p += BIT32SZ;
300 		break;
301 
302 	case Rclunk:
303 	case Rremove:
304 		break;
305 
306 	case Rstat:
307 		if(p+BIT16SZ > ep)
308 			return 0;
309 		f->nstat = GBIT16(p);
310 		p += BIT16SZ;
311 		if(p+f->nstat > ep)
312 			return 0;
313 		f->stat = p;
314 		p += f->nstat;
315 		break;
316 
317 	case Rwstat:
318 		break;
319 	}
320 
321 	if(p==nil || p>ep)
322 		return 0;
323 	if(ap+size == p)
324 		return size;
325 	return 0;
326 }
327