At mount/unmount time, add an exec hook to revoke all vnodes iff the
process is about to exec a sugid binary. To speed up things, use hashing for vnode allocation, like other filesystems do. This avoids walking the whole procfs node list in the revoke case too.
This commit is contained in:
parent
701cc4b663
commit
15bb1bd145
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: procfs.h,v 1.27 1999/09/02 23:33:45 thorpej Exp $ */
|
||||
/* $NetBSD: procfs.h,v 1.28 2000/01/25 21:52:04 fvdl Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
|
@ -63,7 +63,7 @@ typedef enum {
|
|||
* control data for the proc file system.
|
||||
*/
|
||||
struct pfsnode {
|
||||
struct pfsnode *pfs_next; /* next on list */
|
||||
LIST_ENTRY(pfsnode) pfs_hash; /* hash chain */
|
||||
struct vnode *pfs_vnode; /* vnode associated with this pfsnode */
|
||||
pfstype pfs_type; /* type of procfs node */
|
||||
pid_t pfs_pid; /* associated process */
|
||||
|
@ -90,6 +90,14 @@ struct pfsnode {
|
|||
((type) + 2) : \
|
||||
((((pid)+1) << 4) + ((int) (type))))
|
||||
|
||||
struct procfsmount {
|
||||
void *pmnt_exechook;
|
||||
struct mount *pmnt_mp;
|
||||
};
|
||||
|
||||
#define VFSTOPROC(mp) ((struct procfsmount *)(mp)->mnt_data)
|
||||
#define PROCTOVFS(pp) ((pp)->pmnt_mp)
|
||||
|
||||
/*
|
||||
* Convert between pfsnode vnode
|
||||
*/
|
||||
|
@ -127,6 +135,8 @@ int procfs_docmdline __P((struct proc *, struct proc *, struct pfsnode *,
|
|||
struct uio *));
|
||||
|
||||
int procfs_checkioperm __P((struct proc *, struct proc *));
|
||||
void procfs_revoke_vnodes __P((struct proc *, void *));
|
||||
void procfs_hashinit __P((void));
|
||||
|
||||
/* functions to check whether or not files should be displayed */
|
||||
int procfs_validfile __P((struct proc *));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: procfs_subr.c,v 1.28 1999/09/02 23:33:45 thorpej Exp $ */
|
||||
/* $NetBSD: procfs_subr.c,v 1.29 2000/01/25 21:52:04 fvdl Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994 Christopher G. Demetriou. All rights reserved.
|
||||
|
@ -51,8 +51,16 @@
|
|||
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
static struct pfsnode *pfshead;
|
||||
static int pfsvplock;
|
||||
void procfs_hashins __P((struct pfsnode *));
|
||||
void procfs_hashrem __P((struct pfsnode *));
|
||||
struct vnode *procfs_hashget __P((pid_t, pfstype, struct mount *));
|
||||
|
||||
LIST_HEAD(pfs_hashhead, pfsnode) *pfs_hashtbl;
|
||||
u_long ihash; /* size of hash table - 1 */
|
||||
#define PFSPIDHASH(pid) (&pfs_hashtbl[(pid) & ihash])
|
||||
|
||||
struct lock pfs_hashlock;
|
||||
struct simplelock pfs_hash_slock;
|
||||
|
||||
#define ISSET(t, f) ((t) & (f))
|
||||
|
||||
|
@ -91,41 +99,23 @@ procfs_allocvp(mp, vpp, pid, pfs_type)
|
|||
{
|
||||
struct pfsnode *pfs;
|
||||
struct vnode *vp;
|
||||
struct pfsnode **pp;
|
||||
int error;
|
||||
|
||||
loop:
|
||||
for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) {
|
||||
vp = PFSTOV(pfs);
|
||||
if (pfs->pfs_pid == pid &&
|
||||
pfs->pfs_type == pfs_type &&
|
||||
vp->v_mount == mp) {
|
||||
if (vget(vp, LK_EXCLUSIVE))
|
||||
goto loop;
|
||||
*vpp = vp;
|
||||
do {
|
||||
if ((*vpp = procfs_hashget(pid, pfs_type, mp)) != NULL)
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
} while (lockmgr(&pfs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0));
|
||||
|
||||
/*
|
||||
* otherwise lock the vp list while we call getnewvnode
|
||||
* since that can block.
|
||||
*/
|
||||
if (pfsvplock & PROCFS_LOCKED) {
|
||||
pfsvplock |= PROCFS_WANT;
|
||||
sleep((caddr_t) &pfsvplock, PINOD);
|
||||
goto loop;
|
||||
if ((error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp)) != 0) {
|
||||
*vpp = NULL;
|
||||
lockmgr(&pfs_hashlock, LK_RELEASE, 0);
|
||||
return (error);
|
||||
}
|
||||
pfsvplock |= PROCFS_LOCKED;
|
||||
|
||||
if ((error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp)) != 0)
|
||||
goto out;
|
||||
vp = *vpp;
|
||||
|
||||
MALLOC(pfs, void *, sizeof(struct pfsnode), M_TEMP, M_WAITOK);
|
||||
vp->v_data = pfs;
|
||||
|
||||
pfs->pfs_next = 0;
|
||||
pfs->pfs_pid = (pid_t) pid;
|
||||
pfs->pfs_type = pfs_type;
|
||||
pfs->pfs_vnode = vp;
|
||||
|
@ -176,20 +166,8 @@ loop:
|
|||
panic("procfs_allocvp");
|
||||
}
|
||||
|
||||
VOP_LOCK(vp, LK_EXCLUSIVE);
|
||||
|
||||
/* add to procfs vnode list */
|
||||
for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next)
|
||||
continue;
|
||||
*pp = pfs;
|
||||
|
||||
out:
|
||||
pfsvplock &= ~PROCFS_LOCKED;
|
||||
|
||||
if (pfsvplock & PROCFS_WANT) {
|
||||
pfsvplock &= ~PROCFS_WANT;
|
||||
wakeup((caddr_t) &pfsvplock);
|
||||
}
|
||||
procfs_hashins(pfs);
|
||||
lockmgr(&pfs_hashlock, LK_RELEASE, 0);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
@ -198,15 +176,9 @@ int
|
|||
procfs_freevp(vp)
|
||||
struct vnode *vp;
|
||||
{
|
||||
struct pfsnode **pfspp;
|
||||
struct pfsnode *pfs = VTOPFS(vp);
|
||||
|
||||
for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) {
|
||||
if (*pfspp == pfs) {
|
||||
*pfspp = pfs->pfs_next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
procfs_hashrem(pfs);
|
||||
|
||||
FREE(vp->v_data, M_TEMP);
|
||||
vp->v_data = 0;
|
||||
|
@ -336,3 +308,91 @@ vfs_findname(nm, buf, buflen)
|
|||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize pfsnode hash table.
|
||||
*/
|
||||
void
|
||||
procfs_hashinit()
|
||||
{
|
||||
lockinit(&pfs_hashlock, PINOD, "pfs_hashlock", 0, 0);
|
||||
pfs_hashtbl = hashinit(desiredvnodes / 4, M_UFSMNT, M_WAITOK, &ihash);
|
||||
simple_lock_init(&pfs_hash_slock);
|
||||
}
|
||||
|
||||
struct vnode *
|
||||
procfs_hashget(pid, type, mp)
|
||||
pid_t pid;
|
||||
pfstype type;
|
||||
struct mount *mp;
|
||||
{
|
||||
struct pfsnode *pp;
|
||||
struct vnode *vp;
|
||||
|
||||
loop:
|
||||
simple_lock(&pfs_hash_slock);
|
||||
for (pp = PFSPIDHASH(pid)->lh_first; pp; pp = pp->pfs_hash.le_next) {
|
||||
vp = PFSTOV(pp);
|
||||
if (pid == pp->pfs_pid && pp->pfs_type == type &&
|
||||
vp->v_mount == mp) {
|
||||
simple_lock(&vp->v_interlock);
|
||||
simple_unlock(&pfs_hash_slock);
|
||||
if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
|
||||
goto loop;
|
||||
return (vp);
|
||||
}
|
||||
}
|
||||
simple_unlock(&pfs_hash_slock);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert the pfsnode into the hash table and lock it.
|
||||
*/
|
||||
void
|
||||
procfs_hashins(pp)
|
||||
struct pfsnode *pp;
|
||||
{
|
||||
struct pfs_hashhead *ppp;
|
||||
|
||||
/* lock the pfsnode, then put it on the appropriate hash list */
|
||||
lockmgr(&pp->pfs_vnode->v_lock, LK_EXCLUSIVE, (struct simplelock *)0);
|
||||
|
||||
simple_lock(&pfs_hash_slock);
|
||||
ppp = PFSPIDHASH(pp->pfs_pid);
|
||||
LIST_INSERT_HEAD(ppp, pp, pfs_hash);
|
||||
simple_unlock(&pfs_hash_slock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the pfsnode from the hash table.
|
||||
*/
|
||||
void
|
||||
procfs_hashrem(pp)
|
||||
struct pfsnode *pp;
|
||||
{
|
||||
simple_lock(&pfs_hash_slock);
|
||||
LIST_REMOVE(pp, pfs_hash);
|
||||
simple_unlock(&pfs_hash_slock);
|
||||
}
|
||||
|
||||
void
|
||||
procfs_revoke_vnodes(p, arg)
|
||||
struct proc *p;
|
||||
void *arg;
|
||||
{
|
||||
struct pfsnode *pfs, *pnext;
|
||||
struct vnode *vp;
|
||||
struct mount *mp = (struct mount *)arg;
|
||||
|
||||
if (!(p->p_flag & P_SUGID))
|
||||
return;
|
||||
|
||||
for (pfs = PFSPIDHASH(p->p_pid)->lh_first; pfs; pfs = pnext) {
|
||||
vp = PFSTOV(pfs);
|
||||
pnext = pfs->pfs_hash.le_next;
|
||||
if (vp->v_usecount > 0 && pfs->pfs_pid == p->p_pid &&
|
||||
vp->v_mount == mp)
|
||||
VOP_REVOKE(vp, REVOKEALL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: procfs_vfsops.c,v 1.31 1999/02/26 23:44:46 wrstuden Exp $ */
|
||||
/* $NetBSD: procfs_vfsops.c,v 1.32 2000/01/25 21:52:04 fvdl Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
|
@ -57,6 +57,7 @@
|
|||
#include <sys/mount.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <vm/vm.h> /* for PAGE_SIZE */
|
||||
|
||||
|
@ -91,6 +92,7 @@ procfs_mount(mp, path, data, ndp, p)
|
|||
struct proc *p;
|
||||
{
|
||||
size_t size;
|
||||
struct procfsmount *pmnt;
|
||||
|
||||
if (UIO_MX & (UIO_MX-1)) {
|
||||
log(LOG_ERR, "procfs: invalid directory entry size");
|
||||
|
@ -101,13 +103,20 @@ procfs_mount(mp, path, data, ndp, p)
|
|||
return (EOPNOTSUPP);
|
||||
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = 0;
|
||||
pmnt = (struct procfsmount *) malloc(sizeof(struct procfsmount),
|
||||
M_UFSMNT, M_WAITOK); /* XXX need new malloc type */
|
||||
|
||||
mp->mnt_data = (qaddr_t)pmnt;
|
||||
vfs_getnewfsid(mp, MOUNT_PROCFS);
|
||||
|
||||
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN, &size);
|
||||
memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size);
|
||||
memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
|
||||
memcpy(mp->mnt_stat.f_mntfromname, "procfs", sizeof("procfs"));
|
||||
|
||||
pmnt->pmnt_exechook = exechook_establish(procfs_revoke_vnodes, mp);
|
||||
pmnt->pmnt_mp = mp;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -129,6 +138,11 @@ procfs_unmount(mp, mntflags, p)
|
|||
if ((error = vflush(mp, 0, flags)) != 0)
|
||||
return (error);
|
||||
|
||||
exechook_disestablish(VFSTOPROC(mp)->pmnt_exechook);
|
||||
|
||||
free(mp->mnt_data, M_UFSMNT);
|
||||
mp->mnt_data = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -255,6 +269,7 @@ procfs_vptofh(vp, fhp)
|
|||
void
|
||||
procfs_init()
|
||||
{
|
||||
procfs_hashinit();
|
||||
}
|
||||
|
||||
int
|
||||
|
|
Loading…
Reference in New Issue