diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2017-07-20 09:49:46 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2017-07-20 09:49:46 +0000 |
commit | d662ba131db62cabe229d20f1eb9b5103df6bb93 (patch) | |
tree | 125a68fcaf95b5b8b4f250129b23a92866123653 /sys | |
parent | d3bfe8082a3ee8a60f72060905f4c9275867e799 (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.c | 21 |
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. */ |