⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chan.c

📁 在x86平台上运行不可信任代码的sandbox。
💻 C
📖 第 1 页 / 共 3 页
字号:
			e->off[e->nelems] = name+strlen(name) - e->name;			e->mustbedir = 1;			break;		}		growparse(e);		e->elems[e->nelems++] = name;		slash = utfrune(name, '/');		if(slash == nil){			e->off[e->nelems] = name+strlen(name) - e->name;			e->mustbedir = 0;			break;		}		e->off[e->nelems] = slash - e->name;		*slash++ = '\0';		name = slash;	}		if(0 && chandebug){		int i;				print("parsename %s:", e->name);		for(i=0; i<=e->nelems; i++)			print(" %d", e->off[i]);		print("\n");	}}void*memrchr(void *va, int c, long n){	uchar *a, *e;	a = va;	for(e=a+n-1; e>a; e--)		if(*e == c)			return e;	return nil;}voidnamelenerror(char *aname, int len, char *err){	char *ename, *name, *next;	int i, errlen;	/*	 * If the name is short enough, just use the whole thing.	 */	errlen = strlen(err);	if(len < ERRMAX/3 || len+errlen < 2*ERRMAX/3)		snprint(up->genbuf, sizeof up->genbuf, "%.*s", 			utfnlen(aname, len), aname);	else{		/*		 * Print a suffix of the name, but try to get a little info.		 */		ename = aname+len;		next = ename;		do{			name = next;			next = memrchr(aname, '/', name-aname);			if(next == nil)				next = aname;			len = ename-next;		}while(len < ERRMAX/3 || len + errlen < 2*ERRMAX/3);		/*		 * If the name is ridiculously long, chop it.		 */		if(name == ename){			name = ename-ERRMAX/4;			if(name <= aname)				panic("bad math in namelenerror");			/* walk out of current UTF sequence */			for(i=0; (*name&0xC0)==0x80 && i<3; i++)				name++;		}		snprint(up->genbuf, sizeof up->genbuf, "...%.*s",			utfnlen(name, ename-name), name);	}					snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, err);	nexterror();}voidnameerror(char *name, char *err){	namelenerror(name, strlen(name), err);}/* * Turn a name into a channel. * &name[0] is known to be a valid address.  It may be a kernel address. * * Opening with amode Aopen, Acreate, Aremove, or Aaccess guarantees * that the result will be the only reference to that particular fid. * This is necessary since we might pass the result to * devtab[]->remove(). * * Opening Atodir or Amount does not guarantee this. * * Under certain circumstances, opening Aaccess will cause * an unnecessary clone in order to get a cunique Chan so it * can attach the correct name.  Sysstat and sys_stat need the * correct name so they can rewrite the stat info. */Chan*namec(char *aname, int amode, int omode, ulong perm){	int len, n, t, nomount;	Chan *c, *cnew;	Path *path;	Elemlist e;	Rune r;	Mhead *m;	char *createerr, tmperrbuf[ERRMAX];	char *name;	if(aname[0] == '\0')		error("empty file name");	aname = validnamedup(aname, 1);	if(waserror()){		free(aname);		nexterror();	}if(tracesyscalls)	print("\tnamec %s\n", aname);	DBG("namec %s %d %d\n", aname, amode, omode);	name = aname;	/*	 * Find the starting off point (the current slash, the root of	 * a device tree, or the current dot) as well as the name to	 * evaluate starting there.	 */	nomount = 0;	switch(name[0]){	case '/':		c = up->slash;		incref(&c->ref);		break;		case '#':		nomount = 1;		up->genbuf[0] = '\0';		n = 0;		while(*name != '\0' && (*name != '/' || n < 2)){			if(n >= sizeof(up->genbuf)-1)				error(Efilename);			up->genbuf[n++] = *name++;		}		up->genbuf[n] = '\0';		/*		 *  noattach is sandboxing.		 *		 *  the OK exceptions are:		 *	|  it only gives access to pipes you create		 *	d  this process's file descriptors		 *	e  this process's environment		 *  the iffy exceptions are:		 *	c  time and pid, but also cons and consctl		 *	p  control of your own processes (and unfortunately		 *	   any others left unprotected)		 */		n = chartorune(&r, up->genbuf+1)+1;		/* actually / is caught by parsing earlier */		if(utfrune("M", r))			error(Enoattach);		if(up->pgrp->noattach && utfrune("|decp", r)==nil)			error(Enoattach);		t = devno(r, 1);		if(t == -1)			error(Ebadsharp);		c = devtab[t]->attach(up->genbuf+n);		break;	default:		c = up->dot;		incref(&c->ref);		break;	}	e.aname = aname;	e.prefix = name - aname;	e.name = nil;	e.elems = nil;	e.off = nil;	e.nelems = 0;	e.nerror = 0;	if(waserror()){		cclose(c);		free(e.name);		free(e.elems);		/*		 * Prepare nice error, showing first e.nerror elements of name.		 */		if(e.nerror == 0)			nexterror();		strcpy(tmperrbuf, up->errstr);		if(e.off[e.nerror]==0)			print("nerror=%d but off=%d\n",				e.nerror, e.off[e.nerror]);		if(0 && chandebug)			print("showing %d+%d/%d (of %d) of %s (%d %d)\n", e.prefix, e.off[e.nerror], e.nerror, e.nelems, aname, e.off[0], e.off[1]);		len = e.prefix+e.off[e.nerror];		free(e.off);		namelenerror(aname, len, tmperrbuf);	}	/*	 * Build a list of elements in the name.	 */	parsename(name, &e);	/*	 * On create, ....	 */	if(amode == Acreate){		/* perm must have DMDIR if last element is / or /. */		if(e.mustbedir && !(perm&DMDIR)){			e.nerror = e.nelems;			error("create without DMDIR");		}		/* don't try to walk the last path element just yet. */		if(e.nelems == 0)			error(Eexist);		e.nelems--;	}	if(walk(&c, e.elems, e.nelems, nomount, &e.nerror) < 0){		if(e.nerror < 0 || e.nerror > e.nelems){			print("namec %s walk error nerror=%d\n", aname, e.nerror);			e.nerror = 0;		}		nexterror();	}	if(e.mustbedir && !(c->qid.type&QTDIR))		error("not a directory");	if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR))		error("cannot exec directory");	switch(amode){	case Abind:		/* no need to maintain path - cannot dotdot an Abind */		m = nil;		if(!nomount)			domount(&c, &m, nil);		if(c->umh != nil)			putmhead(c->umh);		c->umh = m;		break;	case Aaccess:	case Aremove:	case Aopen:	Open:		/* save&update the name; domount might change c */		path = c->path;		incref(&path->ref);		m = nil;		if(!nomount)			domount(&c, &m, &path);		/* our own copy to open or remove */		c = cunique(c);		/* now it's our copy anyway, we can put the name back */		pathclose(c->path);		c->path = path;		/* record whether c is on a mount point */		c->ismtpt = m!=nil;		switch(amode){		case Aaccess:		case Aremove:			putmhead(m);			break;		case Aopen:		case Acreate:if(c->umh != nil){	print("cunique umh Open\n");	putmhead(c->umh);	c->umh = nil;}			/* only save the mount head if it's a multiple element union */			if(m && m->mount && m->mount->next)				c->umh = m;			else				putmhead(m);			/* save registers else error() in open has wrong value of c saved */			saveregisters();			if(omode == OEXEC)				c->flag &= ~CCACHE;			c = devtab[c->type]->open(c, omode&~OCEXEC);			if(omode & OCEXEC)				c->flag |= CCEXEC;			if(omode & ORCLOSE)				c->flag |= CRCLOSE;			break;		}		break;	case Atodir:		/*		 * Directories (e.g. for cd) are left before the mount point,		 * so one may mount on / or . and see the effect.		 */		if(!(c->qid.type & QTDIR))			error(Enotdir);		break;	case Amount:		/*		 * When mounting on an already mounted upon directory,		 * one wants subsequent mounts to be attached to the		 * original directory, not the replacement.  Don't domount.		 */		break;	case Acreate:		/*		 * We've already walked all but the last element.		 * If the last exists, try to open it OTRUNC.		 * If omode&OEXCL is set, just give up.		 */		e.nelems++;		e.nerror++;		if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){			if(omode&OEXCL)				error(Eexist);			omode |= OTRUNC;			goto Open;		}		/*		 * The semantics of the create(2) system call are that if the		 * file exists and can be written, it is to be opened with truncation.		 * On the other hand, the create(5) message fails if the file exists.		 * If we get two create(2) calls happening simultaneously, 		 * they might both get here and send create(5) messages, but only 		 * one of the messages will succeed.  To provide the expected create(2)		 * semantics, the call with the failed message needs to try the above		 * walk again, opening for truncation.  This correctly solves the 		 * create/create race, in the sense that any observable outcome can		 * be explained as one happening before the other.		 * The create/create race is quite common.  For example, it happens		 * when two rc subshells simultaneously update the same		 * environment variable.		 *		 * The implementation still admits a create/create/remove race:		 * (A) walk to file, fails		 * (B) walk to file, fails		 * (A) create file, succeeds, returns 		 * (B) create file, fails		 * (A) remove file, succeeds, returns		 * (B) walk to file, return failure.		 *		 * This is hardly as common as the create/create race, and is really		 * not too much worse than what might happen if (B) got a hold of a		 * file descriptor and then the file was removed -- either way (B) can't do		 * anything with the result of the create call.  So we don't care about this race.		 *		 * Applications that care about more fine-grained decision of the races		 * can use the OEXCL flag to get at the underlying create(5) semantics;		 * by default we provide the common case.		 *		 * We need to stay behind the mount point in case we		 * need to do the first walk again (should the create fail).		 *		 * We also need to cross the mount point and find the directory		 * in the union in which we should be creating.		 *		 * The channel staying behind is c, the one moving forward is cnew.		 */		m = nil;		cnew = nil;	/* is this assignment necessary? */		if(!waserror()){	/* try create */			if(!nomount && findmount(&cnew, &m, c->type, c->dev, c->qid))				cnew = createdir(cnew, m);			else{				cnew = c;				incref(&cnew->ref);			}			/*			 * We need our own copy of the Chan because we're			 * about to send a create, which will move it.  Once we have			 * our own copy, we can fix the name, which might be wrong			 * if findmount gave us a new Chan.			 */			cnew = cunique(cnew);			pathclose(cnew->path);			cnew->path = c->path;			incref(&cnew->path->ref);			devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm);			poperror();			if(omode & OCEXEC)				cnew->flag |= CCEXEC;			if(omode & ORCLOSE)				cnew->flag |= CRCLOSE;			if(m)				putmhead(m);			cclose(c);			c = cnew;			c->path = addelem(c->path, e.elems[e.nelems-1], nil);			break;		}		/* create failed */		cclose(cnew);		if(m)			putmhead(m);		if(omode & OEXCL)			nexterror();		/* save error */		createerr = up->errstr;		up->errstr = tmperrbuf;		/* note: we depend that walk does not error */		if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){			up->errstr = createerr;			error(createerr);	/* report true error */		}		up->errstr = createerr;		omode |= OTRUNC;		goto Open;	default:		panic("unknown namec access %d\n", amode);	}	/* place final element in genbuf for e.g. exec */	if(e.nelems > 0)		kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf);	else		kstrcpy(up->genbuf, ".", sizeof up->genbuf);	free(e.name);	free(e.elems);	free(e.off);	poperror();	/* e c */	free(aname);	poperror();	/* aname */	return c;}/* * name is valid. skip leading / and ./ as much as possible */char*skipslash(char *name){	while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/')))		name++;	return name;}char isfrog[256]={	/*NUL*/	1, 1, 1, 1, 1, 1, 1, 1,	/*BKS*/	1, 1, 1, 1, 1, 1, 1, 1,	/*DLE*/	1, 1, 1, 1, 1, 1, 1, 1,	/*CAN*/	1, 1, 1, 1, 1, 1, 1, 1,	['/']	1,	[0x7f]	1,};/* * Check that the name *  a) is in valid memory. *  b) is shorter than 2^16 bytes, so it can fit in a 9P string field. *  c) contains no frogs. * The first byte is known to be addressible by the requester, so the * routine works for kernel and user memory both. * The parameter slashok flags whether a slash character is an error * or a valid character. * * The parameter dup flags whether the string should be copied * out of user space before being scanned the second time. * (Otherwise a malicious thread could remove the NUL, causing us * to access unchecked addresses.)  */static char*validname0(char *aname, int slashok, int dup, ulong pc){	char *p, *ename, *name, *s;	uint t;	int c, n;	Rune r;	name = aname;	if(isuaddr(name)){		if(!dup)			print("warning: validname called from %lux with user pointer", pc);		p = name;		t = BY2PG-((ulong)p&(BY2PG-1));		while((ename=vmemchr(p, 0, t)) == nil){			p += t;			t = BY2PG;		}	}else		ename = memchr(name, 0, (1<<16));	if(ename==nil || ename-name>=(1<<16))		error("name too long");	s = nil;	if(dup){		n = ename-name;		s = smalloc(n+1);		memmove(s, name, n);		s[n] = 0;		aname = s;		name = s;		setmalloctag(s, pc);	}		while(*name){		/* all characters above '~' are ok */		c = *(uchar*)name;		if(c >= Runeself)			name += chartorune(&r, name);		else{			if(isfrog[c])				if(!slashok || c!='/'){					snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);					free(s);					error(up->genbuf);			}			name++;		}	}	return s;}voidvalidname(char *aname, int slashok){	validname0(aname, slashok, 0, getcallerpc(&aname));}char*validnamedup(char *aname, int slashok){	return validname0(aname, slashok, 1, getcallerpc(&aname));}voidisdir(Chan *c){	if(c->qid.type & QTDIR)		return;	error(Enotdir);}/* * This is necessary because there are many * pointers to the top of a given mount list: * *	- the mhead in the namespace hash table *	- the mhead in chans returned from findmount: *	  used in namec and then by unionread. *	- the mhead in chans returned from createdir: *	  used in the open/create race protect, which is gone. * * The RWlock in the Mhead protects the mount list it contains. * The mount list is deleted when we cunmount. * The RWlock ensures that nothing is using the mount list at that time. * * It is okay to replace c->mh with whatever you want as  * long as you are sure you have a unique reference to it. * * This comment might belong somewhere else. */voidputmhead(Mhead *m){	if(m && decref(&m->ref) == 0){		m->mount = (Mount*)0xCafeBeef;		free(m);	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -