diff options
author | green <green@FreeBSD.org> | 2000-08-29 11:28:06 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 2000-08-29 11:28:06 +0000 |
commit | 0fa5ae2859837ce45dfa1d212731cbed7a6bf037 (patch) | |
tree | a0487072d9e3fda944c9970116207cd67e21e923 | |
parent | 0290d697a80874eccbc3e0228ae5f2acb2b7522c (diff) | |
download | FreeBSD-src-0fa5ae2859837ce45dfa1d212731cbed7a6bf037.zip FreeBSD-src-0fa5ae2859837ce45dfa1d212731cbed7a6bf037.tar.gz |
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.
-rw-r--r-- | sys/kern/kern_proc.c | 16 | ||||
-rw-r--r-- | sys/kern/uipc_sockbuf.c | 8 | ||||
-rw-r--r-- | sys/kern/uipc_socket.c | 4 | ||||
-rw-r--r-- | sys/kern/uipc_socket2.c | 8 | ||||
-rw-r--r-- | sys/kern/uipc_usrreq.c | 17 | ||||
-rw-r--r-- | sys/sys/proc.h | 2 |
6 files changed, 31 insertions, 24 deletions
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 9fd0f45..4a4282a 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -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); } diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index 3ff1a9c..542ef6e 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -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; } /* diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index f5f1746..7cd4ca7 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -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) { diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index 3ff1a9c..542ef6e 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -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; } /* diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index a0b4072..c4a3326 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -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; diff --git a/sys/sys/proc.h b/sys/sys/proc.h index fb80e5b..6c0d5d0 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -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)); |