1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-19 10:53:58 +00:00

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
This commit is contained in:
Robert Watson 2003-06-15 06:36:19 +00:00
parent a78d3eaffc
commit 44533b1722
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=116384
3 changed files with 58 additions and 23 deletions

View File

@ -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 */

View File

@ -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 @@ quotaoff(td, mp, type)
* 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);

View File

@ -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: