xref: /inferno-os/libkern/convM2S.c (revision 46439007cf417cbd9ac8049bb4122c890097a0fa)
1 #include	"lib9.h"
2 #include	"fcall.h"
3 
4 static
5 uchar*
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*
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
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