diff options
author | rwatson <rwatson@FreeBSD.org> | 2003-06-15 06:36:19 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2003-06-15 06:36:19 +0000 |
commit | 6b6dc4fc6d5771dee77980e23420217b2137ade3 (patch) | |
tree | 13a4be14b7f377da70e71db5204413b42f1da67d /sys/ufs | |
parent | 09805820842e7c37a7760b83e23874d446f42f85 (diff) | |
download | FreeBSD-src-6b6dc4fc6d5771dee77980e23420217b2137ade3.zip FreeBSD-src-6b6dc4fc6d5771dee77980e23420217b2137ade3.tar.gz |
Re-implement kernel access control for quotactl() as found in the
UFS quota implementation. Push some quite broken access control
logic out of ufs_quotactl() into the individual command
implementations in ufs_quota.c; fix that logic. Pass in the thread
argument to any quotactl command that will need to perform access
control.
o quotaon() requires privilege (PRISON_ROOT).
o quotaoff() requires privilege (PRISON_ROOT).
o getquota() requires that:
If the type is USRQUOTA, either the effective uid match the
requested quota ID, that the unprivileged_get_quota flag be
set, or that the thread be privileged (PRISON_ROOT).
If the type is GRPQUOTA, require that either the thread be
a member of the group represented by the requested quota ID,
that the unprivileged_get_quota flag be set, or that the
thread be privileged (PRISON_ROOT).
o setquota() requires privilege (PRISON_ROOT).
o setuse() requires privilege (PRISON_ROOT).
o qsync() requires no special privilege (consistent with what
was present before, but probably not very useful).
Add a new sysctl, security.bsd.unprivileged_get_quota, which when
set to a non-zero value, will permit unprivileged users to query user
quotas with non-matching uids and gids. Set this to 0 by default
to be mostly consistent with the previous behavior (the same for
USRQUOTA, but not for GRPQUOTA).
Obtained from: TrustedBSD Project
Sponsored by: DARPA, Network Associates Laboratories
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ufs/quota.h | 6 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_quota.c | 54 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_vfsops.c | 21 |
3 files changed, 58 insertions, 23 deletions
diff --git a/sys/ufs/ufs/quota.h b/sys/ufs/ufs/quota.h index 60828a3..bcde29f 100644 --- a/sys/ufs/ufs/quota.h +++ b/sys/ufs/ufs/quota.h @@ -183,12 +183,12 @@ void dqinit(void); void dqrele(struct vnode *, struct dquot *); void dquninit(void); int getinoquota(struct inode *); -int getquota(struct mount *, u_long, int, caddr_t); +int getquota(struct thread *, struct mount *, u_long, int, caddr_t); int qsync(struct mount *mp); int quotaoff(struct thread *td, struct mount *, int); int quotaon(struct thread *td, struct mount *, int, caddr_t); -int setquota(struct mount *, u_long, int, caddr_t); -int setuse(struct mount *, u_long, int, caddr_t); +int setquota(struct thread *, struct mount *, u_long, int, caddr_t); +int setuse(struct thread *, struct mount *, u_long, int, caddr_t); vfs_quotactl_t ufs_quotactl; #else /* !_KERNEL */ diff --git a/sys/ufs/ufs/ufs_quota.c b/sys/ufs/ufs/ufs_quota.c index 9bb4344..21c0355 100644 --- a/sys/ufs/ufs/ufs_quota.c +++ b/sys/ufs/ufs/ufs_quota.c @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); #include <sys/namei.h> #include <sys/proc.h> #include <sys/socket.h> +#include <sys/sysctl.h> #include <sys/vnode.h> #include <ufs/ufs/extattr.h> @@ -58,6 +59,13 @@ __FBSDID("$FreeBSD$"); #include <ufs/ufs/ufsmount.h> #include <ufs/ufs/ufs_extern.h> +SYSCTL_DECL(_security_bsd); + +static int unprivileged_get_quota = 0; +SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_get_quota, CTLFLAG_RW, + &unprivileged_get_quota, 0, + "Unprivileged processes may retrieve quotas for other uids and gids"); + static MALLOC_DEFINE(M_DQUOT, "UFS quota", "UFS quota entries"); /* @@ -404,6 +412,10 @@ quotaon(td, mp, type, fname) int error, flags; struct nameidata nd; + error = suser_cred(td->td_ucred, PRISON_ROOT); + if (error) + return (error); + vpp = &ump->um_quotas[type]; NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fname, td); flags = FREAD | FWRITE; @@ -491,6 +503,10 @@ quotaoff(td, mp, type) struct inode *ip; int error; + error = suser_cred(td->td_ucred, PRISON_ROOT); + if (error) + return (error); + if ((qvp = ump->um_quotas[type]) == NULLVP) return (0); ump->um_qflags[type] |= QTF_CLOSING; @@ -546,7 +562,8 @@ again: * Q_GETQUOTA - return current values in a dqblk structure. */ int -getquota(mp, id, type, addr) +getquota(td, mp, id, type, addr) + struct thread *td; struct mount *mp; u_long id; int type; @@ -555,6 +572,27 @@ getquota(mp, id, type, addr) struct dquot *dq; int error; + switch (type) { + case USRQUOTA: + if ((td->td_ucred->cr_uid != id) && !unprivileged_get_quota) { + error = suser_cred(td->td_ucred, PRISON_ROOT); + if (error) + return (error); + } + break; + + case GRPQUOTA: + if (!groupmember(id, td->td_ucred) && !unprivileged_get_quota) { + error = suser_cred(td->td_ucred, PRISON_ROOT); + if (error) + return (error); + } + break; + + default: + return (EINVAL); + } + error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq); if (error) return (error); @@ -567,7 +605,8 @@ getquota(mp, id, type, addr) * Q_SETQUOTA - assign an entire dqblk structure. */ int -setquota(mp, id, type, addr) +setquota(td, mp, id, type, addr) + struct thread *td; struct mount *mp; u_long id; int type; @@ -579,6 +618,10 @@ setquota(mp, id, type, addr) struct dqblk newlim; int error; + error = suser_cred(td->td_ucred, PRISON_ROOT); + if (error) + return (error); + error = copyin(addr, (caddr_t)&newlim, sizeof (struct dqblk)); if (error) return (error); @@ -628,7 +671,8 @@ setquota(mp, id, type, addr) * Q_SETUSE - set current inode and block usage. */ int -setuse(mp, id, type, addr) +setuse(td, mp, id, type, addr) + struct thread *td; struct mount *mp; u_long id; int type; @@ -640,6 +684,10 @@ setuse(mp, id, type, addr) struct dqblk usage; int error; + error = suser_cred(td->td_ucred, PRISON_ROOT); + if (error) + return (error); + error = copyin(addr, (caddr_t)&usage, sizeof (struct dqblk)); if (error) return (error); diff --git a/sys/ufs/ufs/ufs_vfsops.c b/sys/ufs/ufs/ufs_vfsops.c index 320f058..289e08b 100644 --- a/sys/ufs/ufs/ufs_vfsops.c +++ b/sys/ufs/ufs/ufs_vfsops.c @@ -117,27 +117,14 @@ ufs_quotactl(mp, cmds, uid, arg, td) if (uid == -1) uid = td->td_ucred->cr_ruid; cmd = cmds >> SUBCMDSHIFT; - - switch (cmd) { - case Q_SYNC: - break; - case Q_GETQUOTA: - if (uid == td->td_ucred->cr_ruid) - break; - /* FALLTHROUGH */ - default: - if ((error = suser_cred(td->td_ucred, PRISON_ROOT)) != 0) - return (error); - } - type = cmds & SUBCMDMASK; if ((u_int)type >= MAXQUOTAS) return (EINVAL); + if (vfs_busy(mp, LK_NOWAIT, 0, td)) return (0); switch (cmd) { - case Q_QUOTAON: error = quotaon(td, mp, type, arg); break; @@ -147,15 +134,15 @@ ufs_quotactl(mp, cmds, uid, arg, td) break; case Q_SETQUOTA: - error = setquota(mp, uid, type, arg); + error = setquota(td, mp, uid, type, arg); break; case Q_SETUSE: - error = setuse(mp, uid, type, arg); + error = setuse(td, mp, uid, type, arg); break; case Q_GETQUOTA: - error = getquota(mp, uid, type, arg); + error = getquota(td, mp, uid, type, arg); break; case Q_SYNC: |