Introduce support for Mandatory Access Control and extensible

kernel access control.

Invoke appropriate MAC entry points to authorize the following
operations:

        truncate on open()                      (write)
        access()                                (access)
        readlink()                              (readlink)
        chflags(), lchflags(), fchflags()       (setflag)
        chmod(), fchmod(), lchmod()             (setmode)
        chown(), fchown(), lchown()             (setowner)
        utimes(), lutimes(), futimes()          (setutimes)
        truncate(), ftrunfcate()                (write)
        revoke()                                (revoke)
        fhopen()                                (open)
        truncate on fhopen()                    (write)
        extattr_set_fd, extattr_set_file()      (setextattr)
        extattr_get_fd, extattr_get_file()      (getextattr)
        extattr_delete_fd(), extattr_delete_file() (setextattr)

These entry points permit MAC policies to enforce a variety of
protections on vnodes.  More vnode checks to come, especially in
non-native ABIs.

Obtained from:	TrustedBSD Project
Sponsored by:	DARPA, NAI Labs
This commit is contained in:
rwatson 2002-08-01 15:37:12 +00:00
parent 788a8001cc
commit 7af111191c
2 changed files with 190 additions and 20 deletions

View File

@ -733,7 +733,12 @@ open(td, uap)
VATTR_NULL(&vat);
vat.va_size = 0;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
error = VOP_SETATTR(vp, &vat, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_op(td->td_ucred, vp,
MAC_OP_VNODE_WRITE);
if (error == 0)
#endif
error = VOP_SETATTR(vp, &vat, td->td_ucred, td);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
if (error)
@ -1305,6 +1310,11 @@ vn_access(vp, user_flags, cred, td)
flags |= VWRITE;
if (user_flags & X_OK)
flags |= VEXEC;
#ifdef MAC
error = mac_check_vnode_access(cred, vp, flags);
if (error)
return (error);
#endif
if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
error = VOP_ACCESS(vp, flags, cred, td);
}
@ -1746,6 +1756,13 @@ readlink(td, uap)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
#ifdef MAC
error = mac_check_vnode_readlink(td->td_ucred, vp);
if (error) {
vput(vp);
return (error);
}
#endif
if (vp->v_type != VLNK)
error = EINVAL;
else {
@ -1794,9 +1811,16 @@ setfflags(td, vp, flags)
return (error);
VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
VATTR_NULL(&vattr);
vattr.va_flags = flags;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_setflags(td->td_ucred, vp, vattr.va_flags);
if (error == 0) {
#endif
VATTR_NULL(&vattr);
vattr.va_flags = flags;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
#ifdef MAC
}
#endif
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
return (error);
@ -1902,7 +1926,11 @@ setfmode(td, vp, mode)
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
VATTR_NULL(&vattr);
vattr.va_mode = mode & ALLPERMS;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_setmode(td->td_ucred, vp, vattr.va_mode);
if (error == 0)
#endif
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
return error;
@ -2019,7 +2047,12 @@ setfown(td, vp, uid, gid)
VATTR_NULL(&vattr);
vattr.va_uid = uid;
vattr.va_gid = gid;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_setowner(td->td_ucred, vp, vattr.va_uid,
vattr.va_gid);
if (error == 0)
#endif
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
return error;
@ -2178,7 +2211,12 @@ setutimes(td, vp, ts, numtimes, nullflag)
vattr.va_birthtime = ts[2];
if (nullflag)
vattr.va_vaflags |= VA_UTIMES_NULL;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_setutimes(td->td_ucred, vp, vattr.va_atime,
vattr.va_mtime);
if (error == 0)
#endif
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
return error;
@ -2328,6 +2366,10 @@ truncate(td, uap)
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (vp->v_type == VDIR)
error = EISDIR;
#ifdef MAC
else if ((error = mac_check_vnode_op(td->td_ucred, vp,
MAC_OP_VNODE_WRITE))) {}
#endif
else if ((error = vn_writechk(vp)) == 0 &&
(error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td)) == 0) {
VATTR_NULL(&vattr);
@ -2382,6 +2424,10 @@ ftruncate(td, uap)
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (vp->v_type == VDIR)
error = EISDIR;
#ifdef MAC
else if ((error = mac_check_vnode_op(td->td_ucred, vp,
MAC_OP_VNODE_WRITE))) {}
#endif
else if ((error = vn_writechk(vp)) == 0) {
VATTR_NULL(&vattr);
vattr.va_size = SCARG(uap, length);
@ -3073,6 +3119,13 @@ revoke(td, uap)
vput(vp);
return (EINVAL);
}
#ifdef MAC
error = mac_check_vnode_revoke(td->td_ucred, vp);
if (error) {
vput(vp);
return (error);
}
#endif
error = VOP_GETATTR(vp, &vattr, td->td_ucred, td);
if (error) {
vput(vp);
@ -3257,6 +3310,11 @@ fhopen(td, uap)
mode |= VREAD;
if (fmode & O_APPEND)
mode |= VAPPEND;
#ifdef MAC
error = mac_check_vnode_open(td->td_ucred, vp, mode);
if (error)
goto bad;
#endif
if (mode) {
error = VOP_ACCESS(vp, mode, td->td_ucred, td);
if (error)
@ -3270,9 +3328,17 @@ fhopen(td, uap)
}
VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */
VATTR_NULL(vap);
vap->va_size = 0;
error = VOP_SETATTR(vp, vap, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_op(td->td_ucred, vp,
MAC_OP_VNODE_WRITE);
if (error == 0) {
#endif
VATTR_NULL(vap);
vap->va_size = 0;
error = VOP_SETATTR(vp, vap, td->td_ucred, td);
#ifdef MAC
}
#endif
vn_finished_write(mp);
if (error)
goto bad;
@ -3584,6 +3650,13 @@ extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
auio.uio_td = td;
cnt = nbytes;
#ifdef MAC
error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
attrname, &auio);
if (error)
goto done;
#endif
error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
td->td_ucred, td);
cnt -= auio.uio_resid;
@ -3704,6 +3777,13 @@ extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
} else
sizep = &size;
#ifdef MAC
error = mac_check_vnode_getextattr(td->td_ucred, vp, attrnamespace,
attrname, &auio);
if (error)
goto done;
#endif
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
td->td_ucred, td);
@ -3800,6 +3880,11 @@ extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
#ifdef MAC
error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
attrname, NULL);
#endif
error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, td->td_ucred,
td);

View File

@ -733,7 +733,12 @@ open(td, uap)
VATTR_NULL(&vat);
vat.va_size = 0;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
error = VOP_SETATTR(vp, &vat, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_op(td->td_ucred, vp,
MAC_OP_VNODE_WRITE);
if (error == 0)
#endif
error = VOP_SETATTR(vp, &vat, td->td_ucred, td);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
if (error)
@ -1305,6 +1310,11 @@ vn_access(vp, user_flags, cred, td)
flags |= VWRITE;
if (user_flags & X_OK)
flags |= VEXEC;
#ifdef MAC
error = mac_check_vnode_access(cred, vp, flags);
if (error)
return (error);
#endif
if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
error = VOP_ACCESS(vp, flags, cred, td);
}
@ -1746,6 +1756,13 @@ readlink(td, uap)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
#ifdef MAC
error = mac_check_vnode_readlink(td->td_ucred, vp);
if (error) {
vput(vp);
return (error);
}
#endif
if (vp->v_type != VLNK)
error = EINVAL;
else {
@ -1794,9 +1811,16 @@ setfflags(td, vp, flags)
return (error);
VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
VATTR_NULL(&vattr);
vattr.va_flags = flags;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_setflags(td->td_ucred, vp, vattr.va_flags);
if (error == 0) {
#endif
VATTR_NULL(&vattr);
vattr.va_flags = flags;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
#ifdef MAC
}
#endif
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
return (error);
@ -1902,7 +1926,11 @@ setfmode(td, vp, mode)
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
VATTR_NULL(&vattr);
vattr.va_mode = mode & ALLPERMS;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_setmode(td->td_ucred, vp, vattr.va_mode);
if (error == 0)
#endif
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
return error;
@ -2019,7 +2047,12 @@ setfown(td, vp, uid, gid)
VATTR_NULL(&vattr);
vattr.va_uid = uid;
vattr.va_gid = gid;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_setowner(td->td_ucred, vp, vattr.va_uid,
vattr.va_gid);
if (error == 0)
#endif
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
return error;
@ -2178,7 +2211,12 @@ setutimes(td, vp, ts, numtimes, nullflag)
vattr.va_birthtime = ts[2];
if (nullflag)
vattr.va_vaflags |= VA_UTIMES_NULL;
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_setutimes(td->td_ucred, vp, vattr.va_atime,
vattr.va_mtime);
if (error == 0)
#endif
error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
return error;
@ -2328,6 +2366,10 @@ truncate(td, uap)
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (vp->v_type == VDIR)
error = EISDIR;
#ifdef MAC
else if ((error = mac_check_vnode_op(td->td_ucred, vp,
MAC_OP_VNODE_WRITE))) {}
#endif
else if ((error = vn_writechk(vp)) == 0 &&
(error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td)) == 0) {
VATTR_NULL(&vattr);
@ -2382,6 +2424,10 @@ ftruncate(td, uap)
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
if (vp->v_type == VDIR)
error = EISDIR;
#ifdef MAC
else if ((error = mac_check_vnode_op(td->td_ucred, vp,
MAC_OP_VNODE_WRITE))) {}
#endif
else if ((error = vn_writechk(vp)) == 0) {
VATTR_NULL(&vattr);
vattr.va_size = SCARG(uap, length);
@ -3073,6 +3119,13 @@ revoke(td, uap)
vput(vp);
return (EINVAL);
}
#ifdef MAC
error = mac_check_vnode_revoke(td->td_ucred, vp);
if (error) {
vput(vp);
return (error);
}
#endif
error = VOP_GETATTR(vp, &vattr, td->td_ucred, td);
if (error) {
vput(vp);
@ -3257,6 +3310,11 @@ fhopen(td, uap)
mode |= VREAD;
if (fmode & O_APPEND)
mode |= VAPPEND;
#ifdef MAC
error = mac_check_vnode_open(td->td_ucred, vp, mode);
if (error)
goto bad;
#endif
if (mode) {
error = VOP_ACCESS(vp, mode, td->td_ucred, td);
if (error)
@ -3270,9 +3328,17 @@ fhopen(td, uap)
}
VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */
VATTR_NULL(vap);
vap->va_size = 0;
error = VOP_SETATTR(vp, vap, td->td_ucred, td);
#ifdef MAC
error = mac_check_vnode_op(td->td_ucred, vp,
MAC_OP_VNODE_WRITE);
if (error == 0) {
#endif
VATTR_NULL(vap);
vap->va_size = 0;
error = VOP_SETATTR(vp, vap, td->td_ucred, td);
#ifdef MAC
}
#endif
vn_finished_write(mp);
if (error)
goto bad;
@ -3584,6 +3650,13 @@ extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
auio.uio_td = td;
cnt = nbytes;
#ifdef MAC
error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
attrname, &auio);
if (error)
goto done;
#endif
error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
td->td_ucred, td);
cnt -= auio.uio_resid;
@ -3704,6 +3777,13 @@ extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
} else
sizep = &size;
#ifdef MAC
error = mac_check_vnode_getextattr(td->td_ucred, vp, attrnamespace,
attrname, &auio);
if (error)
goto done;
#endif
error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
td->td_ucred, td);
@ -3800,6 +3880,11 @@ extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
#ifdef MAC
error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
attrname, NULL);
#endif
error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, td->td_ucred,
td);