o Restructure vaccess() so as to check for DAC permission to modify the

object before falling back on privilege.  Make vaccess() accept an
  additional optional argument, privused, to determine whether
  privilege was required for vaccess() to return 0.  Add commented
  out capability checks for reference.  Rename some variables to make
  it more clear which modes/uids/etc are associated with the object,
  and which with the access mode.
o Update file system use of vaccess() to pass NULL as the optional
  privused argument.  Once additional patches are applied, suser()
  will no longer set ASU, so privused will permit passing of
  privilege information up the stack to the caller.

Reviewed by:	bde, green, phk, -security, others
Obtained from:	TrustedBSD Project
This commit is contained in:
rwatson 2000-08-29 14:45:49 +00:00
parent 07eb06526c
commit e54ea574fa
13 changed files with 189 additions and 85 deletions

View File

@ -155,7 +155,7 @@ cd9660_access(ap)
}
return (vaccess(vp->v_type, ip->inode.iso_mode, ip->inode.iso_uid,
ip->inode.iso_gid, ap->a_mode, ap->a_cred));
ip->inode.iso_gid, ap->a_mode, ap->a_cred, NULL));
}
static int

View File

@ -125,7 +125,7 @@ devfs_access(ap)
de = de->de_dir;
return (vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid,
ap->a_mode, ap->a_cred));
ap->a_mode, ap->a_cred, NULL));
}
static int

View File

@ -798,7 +798,7 @@ hpfs_access(ap)
}
return (vaccess(vp->v_type, hp->h_mode, hp->h_uid, hp->h_gid,
ap->a_mode, ap->a_cred));
ap->a_mode, ap->a_cred, NULL));
}
/*

View File

@ -277,7 +277,7 @@ msdosfs_access(ap)
}
return (vaccess(vp->v_type, file_mode, pmp->pm_uid, pmp->pm_gid,
ap->a_mode, ap->a_cred));
ap->a_mode, ap->a_cred, NULL));
}
static int

View File

@ -478,7 +478,7 @@ ntfs_access(ap)
}
return (vaccess(vp->v_type, ip->i_mp->ntm_mode, ip->i_mp->ntm_uid,
ip->i_mp->ntm_gid, ap->a_mode, ap->a_cred));
ip->i_mp->ntm_gid, ap->a_mode, ap->a_cred, NULL));
}
/*

View File

@ -155,7 +155,7 @@ cd9660_access(ap)
}
return (vaccess(vp->v_type, ip->inode.iso_mode, ip->inode.iso_uid,
ip->inode.iso_gid, ap->a_mode, ap->a_cred));
ip->inode.iso_gid, ap->a_mode, ap->a_cred, NULL));
}
static int

View File

@ -2986,54 +2986,106 @@ NDFREE(ndp, flags)
}
int
vaccess(type, file_mode, uid, gid, acc_mode, cred)
vaccess(type, file_mode, file_uid, file_gid, acc_mode, cred, privused)
enum vtype type;
mode_t file_mode;
uid_t uid;
gid_t gid;
uid_t file_uid;
gid_t file_gid;
mode_t acc_mode;
struct ucred *cred;
int *privused;
{
mode_t mask;
mode_t dac_granted;
#ifdef CAPABILITIES
mode_t cap_granted;
#endif
/*
* At this point, uid == 0 can do anything.
* XXX: should use suser() ?
* XXX: Should only check root-ness after other checks fail.
* Look for a normal, non-privileged way to access the file/directory
* as requested. If it exists, go with that.
*/
if (cred->cr_uid == 0)
return (0);
mask = 0;
if (privused != NULL)
*privused = 0;
/* Otherwise, check the owner. */
if (cred->cr_uid == uid) {
if (acc_mode & VEXEC)
mask |= S_IXUSR;
if (acc_mode & VREAD)
mask |= S_IRUSR;
if (acc_mode & VWRITE)
mask |= S_IWUSR;
return ((file_mode & mask) == mask ? 0 : EACCES);
}
dac_granted = 0;
/* Otherwise, check for all groups. */
if (groupmember(gid, cred)) {
if (acc_mode & VEXEC)
mask |= S_IXGRP;
if (acc_mode & VREAD)
mask |= S_IRGRP;
if (acc_mode & VWRITE)
mask |= S_IWGRP;
return ((file_mode & mask) == mask ? 0 : EACCES);
/* Check the owner. */
if (cred->cr_uid == file_uid) {
if (file_mode & S_IXUSR)
dac_granted |= VEXEC;
if (file_mode & S_IRUSR)
dac_granted |= VREAD;
if (file_mode & S_IWUSR)
dac_granted |= VWRITE;
if ((acc_mode & dac_granted) == acc_mode)
return (0);
goto privcheck;
}
/* Otherwise, check everyone else. */
if (acc_mode & VEXEC)
mask |= S_IXOTH;
if (acc_mode & VREAD)
mask |= S_IROTH;
if (acc_mode & VWRITE)
mask |= S_IWOTH;
return ((file_mode & mask) == mask ? 0 : EACCES);
/* Otherwise, check the groups (first match) */
if (groupmember(file_gid, cred)) {
if (file_mode & S_IXGRP)
dac_granted |= VEXEC;
if (file_mode & S_IRGRP)
dac_granted |= VREAD;
if (file_mode & S_IWGRP)
dac_granted |= VWRITE;
if ((acc_mode & dac_granted) == acc_mode)
return (0);
goto privcheck;
}
/* Otherwise, check everyone else. */
if (file_mode & S_IXOTH)
dac_granted |= VEXEC;
if (file_mode & S_IROTH)
dac_granted |= VREAD;
if (file_mode & S_IWOTH)
dac_granted |= VWRITE;
if ((acc_mode & dac_granted) == acc_mode)
return (0);
privcheck:
if (!suser_xxx(cred, NULL, PRISON_ROOT)) {
/* XXX audit: privilege used */
if (privused != NULL)
*privused = 1;
return (0);
}
#ifdef CAPABILITIES
/*
* Build a capability mask to determine if the set of capabilities
* satisfies the requirements when combined with the granted mask
* from above.
* For each capability, if the capability is required, bitwise
* or the request type onto the cap_granted mask.
*/
cap_granted = 0;
if ((acc_mode & VEXEC) && ((dac_granted & VEXEC) == 0) &&
!cap_check_xxx(cred, p, CAP_DAC_EXECUTE, PRISON_ROOT))
cap_granted |= VEXEC;
if ((acc_mode & VREAD) && ((dac_granted & VREAD) == 0) &&
!cap_check_xxx(cred, p, CAP_DAC_READ_SEARCH, PRISON_ROOT))
cap_granted |= VREAD;
if ((acc_mode & VWRITE) && ((dac_granted & VWRITE) == 0) &&
!cap_check_xxx(cred, p, CAP_DAC_WRITE, PRISON_ROOT))
cap_granted |= VWRITE;
if ((acc_mode & (cap_granted | dac_granted)) == mode) {
/* XXX audit: privilege used */
if (privused != NULL)
*privused = 1;
return (0);
}
#endif
return (EACCES);
}

View File

@ -2986,54 +2986,106 @@ NDFREE(ndp, flags)
}
int
vaccess(type, file_mode, uid, gid, acc_mode, cred)
vaccess(type, file_mode, file_uid, file_gid, acc_mode, cred, privused)
enum vtype type;
mode_t file_mode;
uid_t uid;
gid_t gid;
uid_t file_uid;
gid_t file_gid;
mode_t acc_mode;
struct ucred *cred;
int *privused;
{
mode_t mask;
mode_t dac_granted;
#ifdef CAPABILITIES
mode_t cap_granted;
#endif
/*
* At this point, uid == 0 can do anything.
* XXX: should use suser() ?
* XXX: Should only check root-ness after other checks fail.
* Look for a normal, non-privileged way to access the file/directory
* as requested. If it exists, go with that.
*/
if (cred->cr_uid == 0)
return (0);
mask = 0;
if (privused != NULL)
*privused = 0;
/* Otherwise, check the owner. */
if (cred->cr_uid == uid) {
if (acc_mode & VEXEC)
mask |= S_IXUSR;
if (acc_mode & VREAD)
mask |= S_IRUSR;
if (acc_mode & VWRITE)
mask |= S_IWUSR;
return ((file_mode & mask) == mask ? 0 : EACCES);
}
dac_granted = 0;
/* Otherwise, check for all groups. */
if (groupmember(gid, cred)) {
if (acc_mode & VEXEC)
mask |= S_IXGRP;
if (acc_mode & VREAD)
mask |= S_IRGRP;
if (acc_mode & VWRITE)
mask |= S_IWGRP;
return ((file_mode & mask) == mask ? 0 : EACCES);
/* Check the owner. */
if (cred->cr_uid == file_uid) {
if (file_mode & S_IXUSR)
dac_granted |= VEXEC;
if (file_mode & S_IRUSR)
dac_granted |= VREAD;
if (file_mode & S_IWUSR)
dac_granted |= VWRITE;
if ((acc_mode & dac_granted) == acc_mode)
return (0);
goto privcheck;
}
/* Otherwise, check everyone else. */
if (acc_mode & VEXEC)
mask |= S_IXOTH;
if (acc_mode & VREAD)
mask |= S_IROTH;
if (acc_mode & VWRITE)
mask |= S_IWOTH;
return ((file_mode & mask) == mask ? 0 : EACCES);
/* Otherwise, check the groups (first match) */
if (groupmember(file_gid, cred)) {
if (file_mode & S_IXGRP)
dac_granted |= VEXEC;
if (file_mode & S_IRGRP)
dac_granted |= VREAD;
if (file_mode & S_IWGRP)
dac_granted |= VWRITE;
if ((acc_mode & dac_granted) == acc_mode)
return (0);
goto privcheck;
}
/* Otherwise, check everyone else. */
if (file_mode & S_IXOTH)
dac_granted |= VEXEC;
if (file_mode & S_IROTH)
dac_granted |= VREAD;
if (file_mode & S_IWOTH)
dac_granted |= VWRITE;
if ((acc_mode & dac_granted) == acc_mode)
return (0);
privcheck:
if (!suser_xxx(cred, NULL, PRISON_ROOT)) {
/* XXX audit: privilege used */
if (privused != NULL)
*privused = 1;
return (0);
}
#ifdef CAPABILITIES
/*
* Build a capability mask to determine if the set of capabilities
* satisfies the requirements when combined with the granted mask
* from above.
* For each capability, if the capability is required, bitwise
* or the request type onto the cap_granted mask.
*/
cap_granted = 0;
if ((acc_mode & VEXEC) && ((dac_granted & VEXEC) == 0) &&
!cap_check_xxx(cred, p, CAP_DAC_EXECUTE, PRISON_ROOT))
cap_granted |= VEXEC;
if ((acc_mode & VREAD) && ((dac_granted & VREAD) == 0) &&
!cap_check_xxx(cred, p, CAP_DAC_READ_SEARCH, PRISON_ROOT))
cap_granted |= VREAD;
if ((acc_mode & VWRITE) && ((dac_granted & VWRITE) == 0) &&
!cap_check_xxx(cred, p, CAP_DAC_WRITE, PRISON_ROOT))
cap_granted |= VWRITE;
if ((acc_mode & (cap_granted | dac_granted)) == mode) {
/* XXX audit: privilege used */
if (privused != NULL)
*privused = 1;
return (0);
}
#endif
return (EACCES);
}

View File

@ -313,7 +313,7 @@ kernfs_access(ap)
if ((amode & VWRITE) && (fmode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0)
return (EPERM);
return (vaccess(vp->v_tag, fmode, 0, 0, ap->a_mode, ap->a_cred));
return (vaccess(vp->v_tag, fmode, 0, 0, ap->a_mode, ap->a_cred, NULL));
}
static int

View File

@ -277,7 +277,7 @@ msdosfs_access(ap)
}
return (vaccess(vp->v_type, file_mode, pmp->pm_uid, pmp->pm_gid,
ap->a_mode, ap->a_cred));
ap->a_mode, ap->a_cred, NULL));
}
static int

View File

@ -478,7 +478,7 @@ ntfs_access(ap)
}
return (vaccess(vp->v_type, ip->i_mp->ntm_mode, ip->i_mp->ntm_uid,
ip->i_mp->ntm_gid, ap->a_mode, ap->a_cred));
ip->i_mp->ntm_gid, ap->a_mode, ap->a_cred, NULL));
}
/*

View File

@ -555,7 +555,7 @@ int spec_vnoperate __P((struct vop_generic_args *));
int speedup_syncer __P((void));
int textvp_fullpath __P((struct proc *p, char **retbuf, char **retfreebuf));
int vaccess __P((enum vtype type, mode_t file_mode, uid_t uid, gid_t gid,
mode_t acc_mode, struct ucred *cred));
mode_t acc_mode, struct ucred *cred, int *privused));
void vattr_null __P((struct vattr *vap));
int vcount __P((struct vnode *vp));
void vdrop __P((struct vnode *));

View File

@ -332,7 +332,7 @@ ufs_access(ap)
return (EPERM);
return (vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
ap->a_mode, ap->a_cred));
ap->a_mode, ap->a_cred, NULL));
}
/* ARGSUSED */