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:
parent
a78d3eaffc
commit
44533b1722
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=116384
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user