plan9fox/sys/src/9/port/auth.c
cinap_lenrek 4a80d9d029 kernel: fix multiple devproc bugs and pid reuse issues
devproc assumes that when we hold the Proc.debug qlock,
the process will be prevented from exiting. but there is
another race where the process has already exited and
the Proc* slot gets reused. to solve this, on process
creation we also have to acquire the debug qlock while
initializing the fields of the process. this also means
newproc() should only initialize fields *not* protected
by the debug qlock.

always acquire the Proc.debug qlock when changing strings
in the proc structure to avoid doublefree on concurrent
update. for changing the user string, we add a procsetuser()
function that does this for auth.c and devcap.

remove pgrpnote() from pgrp.c and replace by static
postnotepg() in devproc.

avoid the assumption that the Proc* entries returned by
proctab() are continuous.

fixed devproc permission issues:
	- make sure only eve can access /proc/trace
	- none should only be allowed to read its own /proc/n/text
	- move Proc.kp checks into procopen()

pid reuse was not handled correctly, as we where only
checking if a pid had a living process, but there still
could be processes expecting a particular parentpid or
noteid.

this is now addressed with reference counted Pid
structures which are organized in a hash table.
read access to the hash table does not require locks
which will be usefull for dtracy later.
2020-02-23 18:00:21 +01:00

166 lines
2.6 KiB
C

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include <authsrv.h>
char *eve;
char hostdomain[DOMLEN];
/*
* return true if current user is eve
*/
int
iseve(void)
{
return strcmp(eve, up->user) == 0;
}
uintptr
sysfversion(va_list list)
{
int msize, arglen, fd;
char *vers;
Chan *c;
fd = va_arg(list, int);
msize = va_arg(list, int);
vers = va_arg(list, char*);
arglen = va_arg(list, int);
validaddr((uintptr)vers, arglen, 1);
/* check there's a NUL in the version string */
if(arglen <= 0 || memchr(vers, 0, arglen) == nil)
error(Ebadarg);
c = fdtochan(fd, ORDWR, 0, 1);
if(waserror()){
cclose(c);
nexterror();
}
msize = mntversion(c, vers, msize, arglen);
cclose(c);
poperror();
return msize;
}
uintptr
sys_fsession(va_list list)
{
int fd;
char *str;
uint len;
/* deprecated; backwards compatibility only */
fd = va_arg(list, int);
str = va_arg(list, char*);
len = va_arg(list, uint);
if(len == 0)
error(Ebadarg);
validaddr((uintptr)str, len, 1);
*str = '\0';
USED(fd);
return 0;
}
uintptr
sysfauth(va_list list)
{
Chan *c, *ac;
char *aname;
int fd;
fd = va_arg(list, int);
aname = va_arg(list, char*);
validaddr((uintptr)aname, 1, 0);
aname = validnamedup(aname, 1);
if(waserror()){
free(aname);
nexterror();
}
c = fdtochan(fd, ORDWR, 0, 1);
if(waserror()){
cclose(c);
nexterror();
}
ac = mntauth(c, aname);
/* at this point ac is responsible for keeping c alive */
poperror(); /* c */
cclose(c);
poperror(); /* aname */
free(aname);
if(waserror()){
cclose(ac);
nexterror();
}
fd = newfd(ac);
if(fd < 0)
error(Enofd);
poperror(); /* ac */
/* always mark it close on exec */
ac->flag |= CCEXEC;
return (uintptr)fd;
}
/*
* called by devcons() for user device
*
* anyone can become none
*/
long
userwrite(char *a, int n)
{
if(n!=4 || strncmp(a, "none", 4)!=0)
error(Eperm);
procsetuser(up, "none");
return n;
}
/*
* called by devcons() for host owner/domain
*
* writing hostowner also sets user
*/
long
hostownerwrite(char *a, int n)
{
char buf[KNAMELEN];
if(!iseve())
error(Eperm);
if(n <= 0)
error(Ebadarg);
if(n >= sizeof buf)
error(Etoolong);
memmove(buf, a, n);
buf[n] = 0;
renameuser(eve, buf);
srvrenameuser(eve, buf);
shrrenameuser(eve, buf);
kstrdup(&eve, buf);
procsetuser(up, buf);
return n;
}
long
hostdomainwrite(char *a, int n)
{
char buf[DOMLEN];
if(!iseve())
error(Eperm);
if(n <= 0 || n >= DOMLEN)
error(Ebadarg);
memset(buf, 0, DOMLEN);
strncpy(buf, a, n);
if(buf[0] == 0)
error(Ebadarg);
memmove(hostdomain, buf, DOMLEN);
return n;
}