xref: /plan9/sys/src/cmd/unix/drawterm/libc/convM2S.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
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