summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2000-10-19 07:53:59 +0000
committerrwatson <rwatson@FreeBSD.org>2000-10-19 07:53:59 +0000
commit9c993b44d071ddf8586d4213d0c379530a097851 (patch)
tree27467f792016e864c11edd8a12421e911fe3efa0
parentbe2e1033657d185aaa5ec90961b64fef7dc02618 (diff)
downloadFreeBSD-src-9c993b44d071ddf8586d4213d0c379530a097851.zip
FreeBSD-src-9c993b44d071ddf8586d4213d0c379530a097851.tar.gz
o Introduce new VOP_ACCESS() flag VADMIN, allowing file systems to perform
"administrative" authorization checks. In most cases, the VADMIN test checks to make sure the credential effective uid is the same as the file owner. o Modify vaccess() to set VADMIN as an available right if the uid is appropriate. o Modify references to uid-based access control operations such that they now always invoke VOP_ACCESS() instead of using hard-coded policy checks. o This allows alternative UFS policies to be implemented by replacing only ufs_access() (such as mandatory system policies). o VOP_ACCESS() requires the caller to hold an exclusive vnode lock on the vnode: I believe that new invocations of VOP_ACCESS() are always called with the lock held. o Some direct checks of the uid remain, largely associated with the QUOTA and SUIDDIR code. Reviewed by: eivind Obtained from: TrustedBSD Project
-rw-r--r--sys/kern/vfs_export.c5
-rw-r--r--sys/kern/vfs_subr.c5
-rw-r--r--sys/sys/vnode.h13
-rw-r--r--sys/ufs/ufs/ufs_lookup.c5
-rw-r--r--sys/ufs/ufs/ufs_vnops.c69
5 files changed, 65 insertions, 32 deletions
diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c
index eb5f5cf..27dcfd3 100644
--- a/sys/kern/vfs_export.c
+++ b/sys/kern/vfs_export.c
@@ -3050,6 +3050,7 @@ vaccess(type, file_mode, file_uid, file_gid, acc_mode, cred, privused)
/* Check the owner. */
if (cred->cr_uid == file_uid) {
+ dac_granted |= VADMIN;
if (file_mode & S_IXUSR)
dac_granted |= VEXEC;
if (file_mode & S_IRUSR)
@@ -3117,6 +3118,10 @@ privcheck:
!cap_check_xxx(cred, NULL, CAP_DAC_WRITE, PRISON_ROOT))
cap_granted |= VWRITE;
+ if ((acc_mode & VADMIN) && ((dac_granted & VADMIN) == 0) &&
+ !cap_check_xxx(cred, NULL, CAP_FOWNER, PRISON_ROOT))
+ cap_granted |= VADMIN;
+
if ((acc_mode & (cap_granted | dac_granted)) == acc_mode) {
/* XXX audit: privilege used */
if (privused != NULL)
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index eb5f5cf..27dcfd3 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -3050,6 +3050,7 @@ vaccess(type, file_mode, file_uid, file_gid, acc_mode, cred, privused)
/* Check the owner. */
if (cred->cr_uid == file_uid) {
+ dac_granted |= VADMIN;
if (file_mode & S_IXUSR)
dac_granted |= VEXEC;
if (file_mode & S_IRUSR)
@@ -3117,6 +3118,10 @@ privcheck:
!cap_check_xxx(cred, NULL, CAP_DAC_WRITE, PRISON_ROOT))
cap_granted |= VWRITE;
+ if ((acc_mode & VADMIN) && ((dac_granted & VADMIN) == 0) &&
+ !cap_check_xxx(cred, NULL, CAP_FOWNER, PRISON_ROOT))
+ cap_granted |= VADMIN;
+
if ((acc_mode & (cap_granted | dac_granted)) == acc_mode) {
/* XXX audit: privilege used */
if (privused != NULL)
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index cbb2095..487767e 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -218,12 +218,13 @@ struct vattr {
/*
* Modes. Some values same as Ixxx entries from inode.h for now.
*/
-#define VSUID 04000 /* set user id on execution */
-#define VSGID 02000 /* set group id on execution */
-#define VSVTX 01000 /* save swapped text even after use */
-#define VREAD 00400 /* read, write, execute permissions */
-#define VWRITE 00200
-#define VEXEC 00100
+#define VADMIN 010000 /* permission to administer vnode */
+#define VSUID 004000 /* set user id on execution */
+#define VSGID 002000 /* set group id on execution */
+#define VSVTX 001000 /* save swapped text even after use */
+#define VREAD 000400 /* read, write, execute permissions */
+#define VWRITE 000200
+#define VEXEC 000100
/*
* Token indicating no attribute value yet assigned.
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index 22387a9..894ee12 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -476,9 +476,8 @@ found:
* implements append-only directories.
*/
if ((dp->i_mode & ISVTX) &&
- suser_xxx(cred, p, PRISON_ROOT) &&
- cred->cr_uid != dp->i_uid &&
- VTOI(tdp)->i_uid != cred->cr_uid) {
+ VOP_ACCESS(vdp, VADMIN, cred, cnp->cn_proc) &&
+ VOP_ACCESS(tdp, VADMIN, cred, cnp->cn_proc)) {
vput(tdp);
return (EPERM);
}
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index 3ac1038..7201d49 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -411,13 +411,17 @@ ufs_setattr(ap)
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
/*
- * Privileged processes in jail() are permitted to modify
- * arbitrary user flags on files, but are not permitted
- * to modify system flags.
+ * Callers may only modify the file flags on objects they
+ * have VADMIN rights for.
*/
- if (cred->cr_uid != ip->i_uid &&
- (error = suser_xxx(cred, p, PRISON_ROOT)))
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, p)))
return (error);
+ /*
+ * Unprivileged processes and privileged processes in
+ * jail() are not permitted to set system flags.
+ * Privileged processes not in jail() may only set system
+ * flags if the securelevel <= 0.
+ */
if (!suser_xxx(cred, NULL, 0)) {
if ((ip->i_flags
& (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) &&
@@ -450,7 +454,8 @@ ufs_setattr(ap)
if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
- if ((error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p)) != 0)
+ if ((error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred,
+ p)) != 0)
return (error);
}
if (vap->va_size != VNOVAL) {
@@ -480,8 +485,15 @@ ufs_setattr(ap)
return (EROFS);
if ((ip->i_flags & SF_SNAPSHOT) != 0)
return (EPERM);
- if (cred->cr_uid != ip->i_uid &&
- (error = suser_xxx(cred, p, PRISON_ROOT)) &&
+ /*
+ * From utimes(2):
+ * If times is NULL, ... The caller must be the owner of
+ * the file, have permission to write the file, or be the
+ * super-user.
+ * If times is non-NULL, ... The caller must be the owner of
+ * the file or be the super-user.
+ */
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, p)) &&
((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
(error = VOP_ACCESS(vp, VWRITE, cred, p))))
return (error);
@@ -529,11 +541,17 @@ ufs_chmod(vp, mode, cred, p)
register struct inode *ip = VTOI(vp);
int error;
- if (cred->cr_uid != ip->i_uid) {
- error = suser_xxx(cred, p, PRISON_ROOT);
- if (error)
+ /*
+ * To modify the permissions on a file, must possess VADMIN
+ * for that file.
+ */
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, p)))
return (error);
- }
+ /*
+ * Privileged processes may set the sticky bit on non-directories,
+ * as well as set the setgid bit on a file with a group that the
+ * process is not a member of.
+ */
if (suser_xxx(cred, NULL, PRISON_ROOT)) {
if (vp->v_type != VDIR && (mode & S_ISTXT))
return (EFTYPE);
@@ -572,11 +590,17 @@ ufs_chown(vp, uid, gid, cred, p)
if (gid == (gid_t)VNOVAL)
gid = ip->i_gid;
/*
- * If we don't own the file, are trying to change the owner
- * of the file, or are not a member of the target group,
- * the caller must be superuser or the call fails.
+ * To modify the ownership of a file, must possess VADMIN
+ * for that file.
+ */
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, p)))
+ return (error);
+ /*
+ * To change the owner of a file, or change the group of a file
+ * to a group of which we are not a member, the caller must
+ * have privilege.
*/
- if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
+ if ((uid != ip->i_uid ||
(gid != ip->i_gid && !groupmember(gid, cred))) &&
(error = suser_xxx(cred, p, PRISON_ROOT)))
return (error);
@@ -1095,15 +1119,14 @@ abortit:
if (xp->i_number == ip->i_number)
panic("ufs_rename: same file");
/*
- * If the parent directory is "sticky", then the user must
- * own the parent directory, or the destination of the rename,
- * otherwise the destination may not be changed (except by
- * root). This implements append-only directories.
+ * If the parent directory is "sticky", then the caller
+ * must possess VADMIN for the parent directory, or the
+ * destination of the rename. This implements append-only
+ * directories.
*/
if ((dp->i_mode & S_ISTXT) &&
- suser_xxx(tcnp->cn_cred, NULL, PRISON_ROOT) &&
- tcnp->cn_cred->cr_uid != dp->i_uid &&
- xp->i_uid != tcnp->cn_cred->cr_uid) {
+ VOP_ACCESS(tdvp, VADMIN, tcnp->cn_cred, p) &&
+ VOP_ACCESS(tvp, VADMIN, tcnp->cn_cred, p)) {
error = EPERM;
goto bad;
}
OpenPOWER on IntegriCloud