Blob
1 #include <u.h>2 #include <libc.h>3 #include <fcall.h>5 static6 uchar*7 gstring(uchar *p, uchar *ep, char **s)8 {9 uint n;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 }25 static26 uchar*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 }40 /*41 * no syntactic checks.42 * three causes for error:43 * 1. message size field is incorrect44 * 2. input buffer too short for its own data (counts too long, etc.)45 * 3. too many names or qids46 * gqid() and gstring() return nil if they would reach beyond buffer.47 * main switch statement checks range and also can fall through48 * to test at end of routine.49 */50 uint51 convM2Su(uchar *ap, uint nap, Fcall *f, int dotu)52 {53 uchar *p, *ep;54 uint i, size;56 p = ap;57 ep = p + nap;59 if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)60 return 0;61 size = GBIT32(p);62 p += BIT32SZ;64 if(size < BIT32SZ+BIT8SZ+BIT16SZ)65 return 0;67 f->type = GBIT8(p);68 p += BIT8SZ;69 f->tag = GBIT16(p);70 p += BIT16SZ;72 switch(f->type)73 {74 default:75 return 0;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;85 case Tflush:86 if(p+BIT16SZ > ep)87 return 0;88 f->oldtag = GBIT16(p);89 p += BIT16SZ;90 break;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 if(dotu){105 if(p+BIT32SZ > ep)106 return 0;107 f->uidnum = GBIT32(p);108 p += BIT32SZ;109 }110 break;112 case Tattach:113 if(p+BIT32SZ > ep)114 return 0;115 f->fid = GBIT32(p);116 p += BIT32SZ;117 if(p+BIT32SZ > ep)118 return 0;119 f->afid = GBIT32(p);120 p += BIT32SZ;121 p = gstring(p, ep, &f->uname);122 if(p == nil)123 break;124 p = gstring(p, ep, &f->aname);125 if(p == nil)126 break;127 f->uidnum = NOUID;128 if(dotu){129 if(p+BIT32SZ > ep)130 return 0;131 f->uidnum = GBIT32(p);132 p += BIT32SZ;133 }134 break;136 case Twalk:137 if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)138 return 0;139 f->fid = GBIT32(p);140 p += BIT32SZ;141 f->newfid = GBIT32(p);142 p += BIT32SZ;143 f->nwname = GBIT16(p);144 p += BIT16SZ;145 if(f->nwname > MAXWELEM)146 return 0;147 for(i=0; i<f->nwname; i++){148 p = gstring(p, ep, &f->wname[i]);149 if(p == nil)150 break;151 }152 break;154 case Topen:155 case Topenfd:156 if(p+BIT32SZ+BIT8SZ > ep)157 return 0;158 f->fid = GBIT32(p);159 p += BIT32SZ;160 f->mode = GBIT8(p);161 p += BIT8SZ;162 break;164 case Tcreate:165 if(p+BIT32SZ > ep)166 return 0;167 f->fid = GBIT32(p);168 p += BIT32SZ;169 p = gstring(p, ep, &f->name);170 if(p == nil)171 break;172 if(p+BIT32SZ+BIT8SZ > ep)173 return 0;174 f->perm = GBIT32(p);175 p += BIT32SZ;176 f->mode = GBIT8(p);177 p += BIT8SZ;178 if(dotu)179 p = gstring(p, ep, &f->extension);180 break;182 case Tread:183 if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)184 return 0;185 f->fid = GBIT32(p);186 p += BIT32SZ;187 f->offset = GBIT64(p);188 p += BIT64SZ;189 f->count = GBIT32(p);190 p += BIT32SZ;191 break;193 case Twrite:194 if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)195 return 0;196 f->fid = GBIT32(p);197 p += BIT32SZ;198 f->offset = GBIT64(p);199 p += BIT64SZ;200 f->count = GBIT32(p);201 p += BIT32SZ;202 if(p+f->count > ep)203 return 0;204 f->data = (char*)p;205 p += f->count;206 break;208 case Tclunk:209 case Tremove:210 if(p+BIT32SZ > ep)211 return 0;212 f->fid = GBIT32(p);213 p += BIT32SZ;214 break;216 case Tstat:217 if(p+BIT32SZ > ep)218 return 0;219 f->fid = GBIT32(p);220 p += BIT32SZ;221 break;223 case Twstat:224 if(p+BIT32SZ+BIT16SZ > ep)225 return 0;226 f->fid = GBIT32(p);227 p += BIT32SZ;228 f->nstat = GBIT16(p);229 p += BIT16SZ;230 if(p+f->nstat > ep)231 return 0;232 f->stat = p;233 p += f->nstat;234 break;236 /*237 */238 case Rversion:239 if(p+BIT32SZ > ep)240 return 0;241 f->msize = GBIT32(p);242 p += BIT32SZ;243 p = gstring(p, ep, &f->version);244 break;246 case Rerror:247 p = gstring(p, ep, &f->ename);248 f->errornum = 0;249 if(dotu){250 if(p+BIT32SZ > ep)251 return 0;252 f->errornum = GBIT32(p);253 p += BIT32SZ;254 }255 break;257 case Rflush:258 break;260 case Rauth:261 p = gqid(p, ep, &f->aqid);262 if(p == nil)263 break;264 break;266 case Rattach:267 p = gqid(p, ep, &f->qid);268 if(p == nil)269 break;270 break;272 case Rwalk:273 if(p+BIT16SZ > ep)274 return 0;275 f->nwqid = GBIT16(p);276 p += BIT16SZ;277 if(f->nwqid > MAXWELEM)278 return 0;279 for(i=0; i<f->nwqid; i++){280 p = gqid(p, ep, &f->wqid[i]);281 if(p == nil)282 break;283 }284 break;286 case Ropen:287 case Ropenfd:288 case Rcreate:289 p = gqid(p, ep, &f->qid);290 if(p == nil)291 break;292 if(p+BIT32SZ > ep)293 return 0;294 f->iounit = GBIT32(p);295 p += BIT32SZ;296 if(f->type == Ropenfd){297 if(p+BIT32SZ > ep)298 return 0;299 f->unixfd = GBIT32(p);300 p += BIT32SZ;301 }302 break;304 case Rread:305 if(p+BIT32SZ > ep)306 return 0;307 f->count = GBIT32(p);308 p += BIT32SZ;309 if(p+f->count > ep)310 return 0;311 f->data = (char*)p;312 p += f->count;313 break;315 case Rwrite:316 if(p+BIT32SZ > ep)317 return 0;318 f->count = GBIT32(p);319 p += BIT32SZ;320 break;322 case Rclunk:323 case Rremove:324 break;326 case Rstat:327 if(p+BIT16SZ > ep)328 return 0;329 f->nstat = GBIT16(p);330 p += BIT16SZ;331 if(p+f->nstat > ep)332 return 0;333 f->stat = p;334 p += f->nstat;335 break;337 case Rwstat:338 break;339 }341 if(p==nil || p>ep)342 return 0;343 if(ap+size == p)344 return size;345 return 0;346 }348 uint349 convM2S(uchar *ap, uint nap, Fcall *f)350 {351 return convM2Su(ap, nap, f, 0);352 }