2015-12-22 12:55:44 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
|
|
* in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <u.h>
|
2017-04-19 23:33:14 +02:00
|
|
|
#include <lib9.h>
|
2016-12-01 00:09:42 +01:00
|
|
|
#include <9P2000.h>
|
2015-12-22 12:55:44 +01:00
|
|
|
|
|
|
|
static
|
|
|
|
uint8_t*
|
|
|
|
gstring(uint8_t *p, uint8_t *ep, char **s)
|
|
|
|
{
|
2016-11-25 17:18:40 +01:00
|
|
|
int n;
|
2015-12-22 12:55:44 +01:00
|
|
|
|
|
|
|
if(p+BIT16SZ > ep)
|
|
|
|
return nil;
|
|
|
|
n = GBIT16(p);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(n < 0)
|
|
|
|
return nil;
|
2015-12-22 12:55:44 +01:00
|
|
|
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
|
|
|
|
uint8_t*
|
|
|
|
gqid(uint8_t *p, uint8_t *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.
|
|
|
|
*/
|
2016-11-25 17:18:40 +01:00
|
|
|
uint32_t
|
|
|
|
convM2S(uint8_t *ap, uint32_t nap, Fcall *f)
|
2015-12-22 12:55:44 +01:00
|
|
|
{
|
|
|
|
uint8_t *p, *ep;
|
2016-11-25 17:18:40 +01:00
|
|
|
uint32_t i, size;
|
2015-12-22 12:55:44 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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; i<f->nwname; 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);
|
|
|
|
break;
|
|
|
|
case Rattach:
|
|
|
|
p = gqid(p, ep, &f->qid);
|
|
|
|
break;
|
|
|
|
case Rwalk:
|
|
|
|
if(p+BIT16SZ > ep)
|
|
|
|
return 0;
|
|
|
|
f->nwqid = GBIT16(p);
|
|
|
|
p += BIT16SZ;
|
|
|
|
if(f->nwqid > MAXWELEM)
|
|
|
|
return 0;
|
|
|
|
for(i=0; i<f->nwqid; 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;
|
|
|
|
}
|