Remove any possibility of hiwat-related race conditions by changing
the chgsbsize() call to use a "subject" pointer (&sb.sb_hiwat) and a u_long target to set it to. The whole thing is splnet(). This fixes a problem that jdp has been able to provoke.
This commit is contained in:
parent
724694be58
commit
255db4f2fa
@ -194,25 +194,33 @@ chgproccnt(uid, diff, max)
|
||||
* Change the total socket buffer size a user has used.
|
||||
*/
|
||||
int
|
||||
chgsbsize(uid, diff, max)
|
||||
chgsbsize(uid, hiwat, to, max)
|
||||
uid_t uid;
|
||||
rlim_t diff;
|
||||
u_long *hiwat;
|
||||
u_long to;
|
||||
rlim_t max;
|
||||
{
|
||||
struct uidinfo *uip;
|
||||
rlim_t diff;
|
||||
int s;
|
||||
|
||||
uip = uifind(uid);
|
||||
if (diff < 0)
|
||||
KASSERT(uip != NULL, ("reducing sbsize: lost count, uid = %d", uid));
|
||||
KASSERT(to >= *hiwat || uip != NULL,
|
||||
("reducing sbsize: lost count, uid = %d", uid));
|
||||
if (uip == NULL)
|
||||
uip = uicreate(uid);
|
||||
s = splnet();
|
||||
diff = to - *hiwat;
|
||||
/* don't allow them to exceed max, but allow subtraction */
|
||||
if (diff > 0 && uip->ui_sbsize + diff > max) {
|
||||
(void)uifree(uip);
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
uip->ui_sbsize += diff;
|
||||
*hiwat = to;
|
||||
(void)uifree(uip);
|
||||
splx(s);
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
@ -420,7 +420,6 @@ sbreserve(sb, cc, so, p)
|
||||
struct socket *so;
|
||||
struct proc *p;
|
||||
{
|
||||
rlim_t delta;
|
||||
|
||||
/*
|
||||
* p will only be NULL when we're in an interrupt
|
||||
@ -428,8 +427,7 @@ sbreserve(sb, cc, so, p)
|
||||
*/
|
||||
if ((u_quad_t)cc > (u_quad_t)sb_max * MCLBYTES / (MSIZE + MCLBYTES))
|
||||
return (0);
|
||||
delta = (rlim_t)cc - sb->sb_hiwat;
|
||||
if (p && !chgsbsize(so->so_cred->cr_uid, delta,
|
||||
if (p && !chgsbsize(so->so_cred->cr_uid, &sb->sb_hiwat, cc,
|
||||
p->p_rlimit[RLIMIT_SBSIZE].rlim_cur)) {
|
||||
return (0);
|
||||
}
|
||||
@ -450,8 +448,8 @@ sbrelease(sb, so)
|
||||
{
|
||||
|
||||
sbflush(sb);
|
||||
(void)chgsbsize(so->so_cred->cr_uid, -(rlim_t)sb->sb_hiwat, RLIM_INFINITY);
|
||||
sb->sb_hiwat = sb->sb_mbmax = 0;
|
||||
(void)chgsbsize(so->so_cred->cr_uid, &sb->sb_hiwat, 0, RLIM_INFINITY);
|
||||
sb->sb_mbmax = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -191,10 +191,10 @@ sodealloc(so)
|
||||
so->so_gencnt = ++so_gencnt;
|
||||
if (so->so_rcv.sb_hiwat)
|
||||
(void)chgsbsize(so->so_cred->cr_uid,
|
||||
-(rlim_t)so->so_rcv.sb_hiwat, RLIM_INFINITY);
|
||||
&so->so_rcv.sb_hiwat, 0, RLIM_INFINITY);
|
||||
if (so->so_snd.sb_hiwat)
|
||||
(void)chgsbsize(so->so_cred->cr_uid,
|
||||
-(rlim_t)so->so_snd.sb_hiwat, RLIM_INFINITY);
|
||||
&so->so_snd.sb_hiwat, 0, RLIM_INFINITY);
|
||||
if (so->so_accf != NULL) {
|
||||
if (so->so_accf->so_accept_filter != NULL &&
|
||||
so->so_accf->so_accept_filter->accf_destroy != NULL) {
|
||||
|
@ -420,7 +420,6 @@ sbreserve(sb, cc, so, p)
|
||||
struct socket *so;
|
||||
struct proc *p;
|
||||
{
|
||||
rlim_t delta;
|
||||
|
||||
/*
|
||||
* p will only be NULL when we're in an interrupt
|
||||
@ -428,8 +427,7 @@ sbreserve(sb, cc, so, p)
|
||||
*/
|
||||
if ((u_quad_t)cc > (u_quad_t)sb_max * MCLBYTES / (MSIZE + MCLBYTES))
|
||||
return (0);
|
||||
delta = (rlim_t)cc - sb->sb_hiwat;
|
||||
if (p && !chgsbsize(so->so_cred->cr_uid, delta,
|
||||
if (p && !chgsbsize(so->so_cred->cr_uid, &sb->sb_hiwat, cc,
|
||||
p->p_rlimit[RLIMIT_SBSIZE].rlim_cur)) {
|
||||
return (0);
|
||||
}
|
||||
@ -450,8 +448,8 @@ sbrelease(sb, so)
|
||||
{
|
||||
|
||||
sbflush(sb);
|
||||
(void)chgsbsize(so->so_cred->cr_uid, -(rlim_t)sb->sb_hiwat, RLIM_INFINITY);
|
||||
sb->sb_hiwat = sb->sb_mbmax = 0;
|
||||
(void)chgsbsize(so->so_cred->cr_uid, &sb->sb_hiwat, 0, RLIM_INFINITY);
|
||||
sb->sb_mbmax = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -217,6 +217,7 @@ uipc_rcvd(struct socket *so, int flags)
|
||||
{
|
||||
struct unpcb *unp = sotounpcb(so);
|
||||
struct socket *so2;
|
||||
u_long newhiwat;
|
||||
|
||||
if (unp == 0)
|
||||
return EINVAL;
|
||||
@ -235,9 +236,10 @@ uipc_rcvd(struct socket *so, int flags)
|
||||
*/
|
||||
so2->so_snd.sb_mbmax += unp->unp_mbcnt - so->so_rcv.sb_mbcnt;
|
||||
unp->unp_mbcnt = so->so_rcv.sb_mbcnt;
|
||||
so2->so_snd.sb_hiwat += unp->unp_cc - so->so_rcv.sb_cc;
|
||||
(void)chgsbsize(so2->so_cred->cr_uid,
|
||||
(rlim_t)unp->unp_cc - so->so_rcv.sb_cc, RLIM_INFINITY);
|
||||
newhiwat = so2->so_snd.sb_hiwat + unp->unp_cc -
|
||||
so->so_rcv.sb_cc;
|
||||
(void)chgsbsize(so2->so_cred->cr_uid, &so2->so_snd.sb_hiwat,
|
||||
newhiwat, RLIM_INFINITY);
|
||||
unp->unp_cc = so->so_rcv.sb_cc;
|
||||
sowwakeup(so2);
|
||||
break;
|
||||
@ -257,6 +259,7 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
||||
int error = 0;
|
||||
struct unpcb *unp = sotounpcb(so);
|
||||
struct socket *so2;
|
||||
u_long newhiwat;
|
||||
|
||||
if (unp == 0) {
|
||||
error = EINVAL;
|
||||
@ -342,10 +345,10 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
||||
so->so_snd.sb_mbmax -=
|
||||
so2->so_rcv.sb_mbcnt - unp->unp_conn->unp_mbcnt;
|
||||
unp->unp_conn->unp_mbcnt = so2->so_rcv.sb_mbcnt;
|
||||
so->so_snd.sb_hiwat -=
|
||||
so2->so_rcv.sb_cc - unp->unp_conn->unp_cc;
|
||||
(void)chgsbsize(so->so_cred->cr_uid,
|
||||
(rlim_t)unp->unp_conn->unp_cc - so2->so_rcv.sb_cc, RLIM_INFINITY);
|
||||
newhiwat = so->so_snd.sb_hiwat -
|
||||
(so2->so_rcv.sb_cc - unp->unp_conn->unp_cc);
|
||||
(void)chgsbsize(so->so_cred->cr_uid, &so->so_snd.sb_hiwat,
|
||||
newhiwat, RLIM_INFINITY);
|
||||
unp->unp_conn->unp_cc = so2->so_rcv.sb_cc;
|
||||
sorwakeup(so2);
|
||||
m = 0;
|
||||
|
@ -422,7 +422,7 @@ struct vm_zone;
|
||||
extern struct vm_zone *proc_zone;
|
||||
|
||||
int chgproccnt __P((uid_t uid, int diff, int max));
|
||||
int chgsbsize __P((uid_t uid, rlim_t diff, rlim_t max));
|
||||
int chgsbsize __P((uid_t uid, u_long *hiwat, u_long to, rlim_t max));
|
||||
int enterpgrp __P((struct proc *p, pid_t pgid, int mksess));
|
||||
void fixjobc __P((struct proc *p, struct pgrp *pgrp, int entering));
|
||||
int inferior __P((struct proc *p));
|
||||
|
Loading…
Reference in New Issue
Block a user