#include "dat.h" #include "fns.h" #include "error.h" static uchar* gstring(uchar *p, uchar *ep, char **s) { uint n; if(p+BIT16SZ > ep) return nil; n = GBIT16(p); p += BIT16SZ - 1; if(p+n+1 > ep) return nil; /* move it down, on top of count, to make room for '\0' */ memmove(p, p + 1, n); p[n] = '\0'; *s = (char*)p; p += n+1; return p; } static uchar* gqid(uchar *p, uchar *ep, Qid *q) { if(p+QIDSZ > ep) return nil; q->type = GBIT8(p); p += BIT8SZ; q->vers = GBIT32(p); p += BIT32SZ; q->path = GBIT64(p); p += BIT64SZ; return p; } /* * no syntactic checks. * three causes for error: * 1. message size field is incorrect * 2. input buffer too short for its own data (counts too long, etc.) * 3. too many names or qids * gqid() and gstring() return nil if they would reach beyond buffer. * main switch statement checks range and also can fall through * to test at end of routine. */ uint convM2S(uchar *ap, uint nap, Fcall *f) { uchar *p, *ep; uint i, size; p = ap; ep = p + nap; if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) return 0; size = GBIT32(p); p += BIT32SZ; if(size < BIT32SZ+BIT8SZ+BIT16SZ) return 0; f->type = GBIT8(p); p += BIT8SZ; f->tag = GBIT16(p); p += BIT16SZ; switch(f->type) { default: return 0; case Tversion: if(p+BIT32SZ > ep) return 0; f->msize = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->version); break; case Tflush: if(p+BIT16SZ > ep) return 0; f->oldtag = GBIT16(p); p += BIT16SZ; break; case Tauth: if(p+BIT32SZ > ep) return 0; f->afid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->uname); if(p == nil) break; p = gstring(p, ep, &f->aname); if(p == nil) break; break; case Tattach: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; if(p+BIT32SZ > ep) return 0; f->afid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->uname); if(p == nil) break; p = gstring(p, ep, &f->aname); if(p == nil) break; break; case Twalk: if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->newfid = GBIT32(p); p += BIT32SZ; f->nwname = GBIT16(p); p += BIT16SZ; if(f->nwname > MAXWELEM) return 0; for(i=0; inwname; i++){ p = gstring(p, ep, &f->wname[i]); if(p == nil) break; } break; case Topen: if(p+BIT32SZ+BIT8SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->mode = GBIT8(p); p += BIT8SZ; break; case Tcreate: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->name); if(p == nil) break; if(p+BIT32SZ+BIT8SZ > ep) return 0; f->perm = GBIT32(p); p += BIT32SZ; f->mode = GBIT8(p); p += BIT8SZ; break; case Tread: if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->offset = GBIT64(p); p += BIT64SZ; f->count = GBIT32(p); p += BIT32SZ; break; case Twrite: if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->offset = GBIT64(p); p += BIT64SZ; f->count = GBIT32(p); p += BIT32SZ; if(p+f->count > ep) return 0; f->data = (char*)p; p += f->count; break; case Tclunk: case Tremove: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; break; case Tstat: if(p+BIT32SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; break; case Twstat: if(p+BIT32SZ+BIT16SZ > ep) return 0; f->fid = GBIT32(p); p += BIT32SZ; f->nstat = GBIT16(p); p += BIT16SZ; if(p+f->nstat > ep) return 0; f->stat = p; p += f->nstat; break; /* */ case Rversion: if(p+BIT32SZ > ep) return 0; f->msize = GBIT32(p); p += BIT32SZ; p = gstring(p, ep, &f->version); break; case Rerror: p = gstring(p, ep, &f->ename); break; case Rflush: break; case Rauth: p = gqid(p, ep, &f->aqid); if(p == nil) break; break; case Rattach: p = gqid(p, ep, &f->qid); if(p == nil) break; break; case Rwalk: if(p+BIT16SZ > ep) return 0; f->nwqid = GBIT16(p); p += BIT16SZ; if(f->nwqid > MAXWELEM) return 0; for(i=0; inwqid; i++){ p = gqid(p, ep, &f->wqid[i]); if(p == nil) break; } break; case Ropen: case Rcreate: p = gqid(p, ep, &f->qid); if(p == nil) break; if(p+BIT32SZ > ep) return 0; f->iounit = GBIT32(p); p += BIT32SZ; break; case Rread: if(p+BIT32SZ > ep) return 0; f->count = GBIT32(p); p += BIT32SZ; if(p+f->count > ep) return 0; f->data = (char*)p; p += f->count; break; case Rwrite: if(p+BIT32SZ > ep) return 0; f->count = GBIT32(p); p += BIT32SZ; break; case Rclunk: case Rremove: break; case Rstat: if(p+BIT16SZ > ep) return 0; f->nstat = GBIT16(p); p += BIT16SZ; if(p+f->nstat > ep) return 0; f->stat = p; p += f->nstat; break; case Rwstat: break; } if(p==nil || p>ep) return 0; if(ap+size == p) return size; return 0; } static uchar* pstring(uchar *p, char *s) { uint n; if(s == nil){ PBIT16(p, 0); p += BIT16SZ; return p; } n = strlen(s); PBIT16(p, n); p += BIT16SZ; memmove(p, s, n); p += n; return p; } static uchar* pqid(uchar *p, Qid *q) { PBIT8(p, q->type); p += BIT8SZ; PBIT32(p, q->vers); p += BIT32SZ; PBIT64(p, q->path); p += BIT64SZ; return p; } static uint stringsz(char *s) { if(s == nil) return BIT16SZ; return BIT16SZ+strlen(s); } uint sizeS2M(Fcall *f) { uint n; int i; n = 0; n += BIT32SZ; /* size */ n += BIT8SZ; /* type */ n += BIT16SZ; /* tag */ switch(f->type) { default: return 0; case Tversion: n += BIT32SZ; n += stringsz(f->version); break; case Tflush: n += BIT16SZ; break; case Tauth: n += BIT32SZ; n += stringsz(f->uname); n += stringsz(f->aname); break; case Tattach: n += BIT32SZ; n += BIT32SZ; n += stringsz(f->uname); n += stringsz(f->aname); break; case Twalk: n += BIT32SZ; n += BIT32SZ; n += BIT16SZ; for(i=0; inwname; i++) n += stringsz(f->wname[i]); break; case Topen: n += BIT32SZ; n += BIT8SZ; break; case Tcreate: n += BIT32SZ; n += stringsz(f->name); n += BIT32SZ; n += BIT8SZ; break; case Tread: n += BIT32SZ; n += BIT64SZ; n += BIT32SZ; break; case Twrite: n += BIT32SZ; n += BIT64SZ; n += BIT32SZ; n += f->count; break; case Tclunk: case Tremove: n += BIT32SZ; break; case Tstat: n += BIT32SZ; break; case Twstat: n += BIT32SZ; n += BIT16SZ; n += f->nstat; break; /* */ case Rversion: n += BIT32SZ; n += stringsz(f->version); break; case Rerror: n += stringsz(f->ename); break; case Rflush: break; case Rauth: n += QIDSZ; break; case Rattach: n += QIDSZ; break; case Rwalk: n += BIT16SZ; n += f->nwqid*QIDSZ; break; case Ropen: case Rcreate: n += QIDSZ; n += BIT32SZ; break; case Rread: n += BIT32SZ; n += f->count; break; case Rwrite: n += BIT32SZ; break; case Rclunk: break; case Rremove: break; case Rstat: n += BIT16SZ; n += f->nstat; break; case Rwstat: break; } return n; } uint convS2M(Fcall *f, uchar *ap, uint nap) { uchar *p; uint i, size; size = sizeS2M(f); if(size == 0) return 0; if(size > nap) return 0; p = (uchar*)ap; PBIT32(p, size); p += BIT32SZ; PBIT8(p, f->type); p += BIT8SZ; PBIT16(p, f->tag); p += BIT16SZ; switch(f->type) { default: return 0; case Tversion: PBIT32(p, f->msize); p += BIT32SZ; p = pstring(p, f->version); break; case Tflush: PBIT16(p, f->oldtag); p += BIT16SZ; break; case Tauth: PBIT32(p, f->afid); p += BIT32SZ; p = pstring(p, f->uname); p = pstring(p, f->aname); break; case Tattach: PBIT32(p, f->fid); p += BIT32SZ; PBIT32(p, f->afid); p += BIT32SZ; p = pstring(p, f->uname); p = pstring(p, f->aname); break; case Twalk: PBIT32(p, f->fid); p += BIT32SZ; PBIT32(p, f->newfid); p += BIT32SZ; PBIT16(p, f->nwname); p += BIT16SZ; if(f->nwname > MAXWELEM) return 0; for(i=0; inwname; i++) p = pstring(p, f->wname[i]); break; case Topen: PBIT32(p, f->fid); p += BIT32SZ; PBIT8(p, f->mode); p += BIT8SZ; break; case Tcreate: PBIT32(p, f->fid); p += BIT32SZ; p = pstring(p, f->name); PBIT32(p, f->perm); p += BIT32SZ; PBIT8(p, f->mode); p += BIT8SZ; break; case Tread: PBIT32(p, f->fid); p += BIT32SZ; PBIT64(p, f->offset); p += BIT64SZ; PBIT32(p, f->count); p += BIT32SZ; break; case Twrite: PBIT32(p, f->fid); p += BIT32SZ; PBIT64(p, f->offset); p += BIT64SZ; PBIT32(p, f->count); p += BIT32SZ; memmove(p, f->data, f->count); p += f->count; break; case Tclunk: case Tremove: PBIT32(p, f->fid); p += BIT32SZ; break; case Tstat: PBIT32(p, f->fid); p += BIT32SZ; break; case Twstat: PBIT32(p, f->fid); p += BIT32SZ; PBIT16(p, f->nstat); p += BIT16SZ; memmove(p, f->stat, f->nstat); p += f->nstat; break; /* */ case Rversion: PBIT32(p, f->msize); p += BIT32SZ; p = pstring(p, f->version); break; case Rerror: p = pstring(p, f->ename); break; case Rflush: break; case Rauth: p = pqid(p, &f->aqid); break; case Rattach: p = pqid(p, &f->qid); break; case Rwalk: PBIT16(p, f->nwqid); p += BIT16SZ; if(f->nwqid > MAXWELEM) return 0; for(i=0; inwqid; i++) p = pqid(p, &f->wqid[i]); break; case Ropen: case Rcreate: p = pqid(p, &f->qid); PBIT32(p, f->iounit); p += BIT32SZ; break; case Rread: PBIT32(p, f->count); p += BIT32SZ; memmove(p, f->data, f->count); p += f->count; break; case Rwrite: PBIT32(p, f->count); p += BIT32SZ; break; case Rclunk: break; case Rremove: break; case Rstat: PBIT16(p, f->nstat); p += BIT16SZ; memmove(p, f->stat, f->nstat); p += f->nstat; break; case Rwstat: break; } if(size != p-ap) return 0; return size; }