summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2017-07-20 09:49:46 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2017-07-20 09:49:46 +0000
commitd662ba131db62cabe229d20f1eb9b5103df6bb93 (patch)
tree125a68fcaf95b5b8b4f250129b23a92866123653 /sys
parentd3bfe8082a3ee8a60f72060905f4c9275867e799 (diff)
If pool_get() sleeps while allocating additional memory for socket
splicing, another process may allocate it in the meantime. Then one of the splicing structures leaked in sosplice(). Recheck that no struct sosplice exists after a protential sleep. reported by Ilja Van Sprundel; OK mpi@
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/uipc_socket.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index c1cca893b2e..572f704aec3 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_socket.c,v 1.195 2017/07/20 08:23:43 mpi Exp $ */
+/* $OpenBSD: uipc_socket.c,v 1.196 2017/07/20 09:49:45 bluhm Exp $ */
/* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */
/*
@@ -1073,6 +1073,7 @@ sosplice(struct socket *so, int fd, off_t max, struct timeval *tv)
{
struct file *fp;
struct socket *sosp;
+ struct sosplice *sp;
int s, error = 0;
if (sosplice_taskq == NULL)
@@ -1087,8 +1088,13 @@ sosplice(struct socket *so, int fd, off_t max, struct timeval *tv)
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
(so->so_proto->pr_flags & PR_CONNREQUIRED))
return (ENOTCONN);
- if (so->so_sp == NULL)
- so->so_sp = pool_get(&sosplice_pool, PR_WAITOK | PR_ZERO);
+ if (so->so_sp == NULL) {
+ sp = pool_get(&sosplice_pool, PR_WAITOK | PR_ZERO);
+ if (so->so_sp == NULL)
+ so->so_sp = sp;
+ else
+ pool_put(&sosplice_pool, sp);
+ }
/* If no fd is given, unsplice by removing existing link. */
if (fd < 0) {
@@ -1116,8 +1122,13 @@ sosplice(struct socket *so, int fd, off_t max, struct timeval *tv)
if ((error = getsock(curproc, fd, &fp)) != 0)
return (error);
sosp = fp->f_data;
- if (sosp->so_sp == NULL)
- sosp->so_sp = pool_get(&sosplice_pool, PR_WAITOK | PR_ZERO);
+ if (sosp->so_sp == NULL) {
+ sp = pool_get(&sosplice_pool, PR_WAITOK | PR_ZERO);
+ if (sosp->so_sp == NULL)
+ sosp->so_sp = sp;
+ else
+ pool_put(&sosplice_pool, sp);
+ }
s = solock(so);
/* Lock both receive and send buffer. */