summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2003-06-15 06:36:19 +0000
committerrwatson <rwatson@FreeBSD.org>2003-06-15 06:36:19 +0000
commit6b6dc4fc6d5771dee77980e23420217b2137ade3 (patch)
tree13a4be14b7f377da70e71db5204413b42f1da67d /sys/ufs
parent09805820842e7c37a7760b83e23874d446f42f85 (diff)
downloadFreeBSD-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.h6
-rw-r--r--sys/ufs/ufs/ufs_quota.c54
-rw-r--r--sys/ufs/ufs/ufs_vfsops.c21
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:
OpenPOWER on IntegriCloud