blob: 93819e41f96bbe52fc1258ea7d2b2b547adfae7f [file] [log] [blame] [edit]
// INFERNO
#include <vfs.h>
#include <kfs.h>
#include <slab.h>
#include <kmalloc.h>
#include <kref.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <error.h>
#include <cpio.h>
#include <pmap.h>
#include <smp.h>
#include <ip.h>
static
uint8_t *gstring(uint8_t * p, uint8_t * ep, char **s)
{
unsigned int n;
if (p + BIT16SZ > ep)
return NULL;
n = GBIT16(p);
p += BIT16SZ - 1;
if (p + n + 1 > ep)
return NULL;
/* 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, struct qid *q)
{
if (p + QIDSZ > ep)
return NULL;
q->type = GBIT8(p);
p += BIT8SZ;
q->vers = GBIT32(p);
p += BIT32SZ;
q->path = GBIT64(p);
p += BIT64SZ;
return p;
}
void init_empty_dir(struct dir *d)
{
d->type = ~0;
d->dev = ~0;
d->qid.path = ~0;
d->qid.vers = ~0;
d->qid.type = ~0;
d->mode = ~0;
d->atime = ~0;
d->mtime = ~0;
d->length = ~0;
d->name = "";
d->uid = "";
d->gid = "";
d->muid = "";
}
/*
* 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 NULL if they would reach beyond buffer.
* main switch statement checks range and also can fall through
* to test at end of routine.
*/
unsigned int convM2S(uint8_t * ap, unsigned int nap, struct fcall *f)
{
uint8_t *p, *ep;
unsigned int 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 == NULL)
break;
p = gstring(p, ep, &f->aname);
if (p == NULL)
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 == NULL)
break;
p = gstring(p, ep, &f->aname);
if (p == NULL)
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; i < f->nwname; i++) {
p = gstring(p, ep, &f->wname[i]);
if (p == NULL)
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 == NULL)
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 == NULL)
break;
break;
case Rattach:
p = gqid(p, ep, &f->qid);
if (p == NULL)
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; i < f->nwqid; i++) {
p = gqid(p, ep, &f->wqid[i]);
if (p == NULL)
break;
}
break;
case Ropen:
case Rcreate:
p = gqid(p, ep, &f->qid);
if (p == NULL)
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 == NULL || p > ep)
return 0;
if (ap + size == p)
return size;
return 0;
}